PageSourceSearch

https://www.wijkopenautos.be/static/lp/indigo//js/core.min.js?v=199c3e7bb29af24f3f75

js wijkopenautos.be collected 2026-10-01 15:16:00 UTC 398,751 bytes, 12,233 lines download raw bytes

1/******/ (function(modules) { // webpackBootstrap
2/******/ 	// The module cache
3/******/ 	var installedModules = {};
4
5/******/ 	// The require function
6/******/ 	function __webpack_require__(moduleId) {
7
8/******/ 		// Check if module is in cache
9/******/ 		if(installedModules[moduleId])
10/******/ 			return installedModules[moduleId].exports;
11
12/******/ 		// Create a new module (and put it into the cache)
13/******/ 		var module = installedModules[moduleId] = {
14/******/ 			exports: {},
15/******/ 			id: moduleId,
16/******/ 			loaded: false
17/******/ 		};
18
19/******/ 		// Execute the module function
20/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21
22/******/ 		// Flag the module as loaded
23/******/ 		module.loaded = true;
24
25/******/ 		// Return the exports of the module
26/******/ 		return module.exports;
27/******/ 	}
28
29
30/******/ 	// expose the modules object (__webpack_modules__)
31/******/ 	__webpack_require__.m = modules;
32
33/******/ 	// expose the module cache
34/******/ 	__webpack_require__.c = installedModules;
35
36/******/ 	// __webpack_public_path__
37/******/ 	__webpack_require__.p = "";
38
39/******/ 	// Load entry module and return exports
40/******/ 	return __webpack_require__(0);
41/******/ })
42/************************************************************************/
43/******/ ({
44
45/***/ 0:
46/***/ (function(module, exports, __webpack_require__) {
47
48	__webpack_require__(314);
49	__webpack_require__(315);
50	__webpack_require__(273);
51	__webpack_require__(316);
52	__webpack_require__(317);
53	__webpack_require__(318);
54	__webpack_require__(319);
55	__webpack_require__(320);
56	__webpack_require__(321);
57
58	__webpack_require__(322);
59	__webpack_require__(284);
60	__webpack_require__(324);
61	__webpack_require__(289);
62	__webpack_require__(281);
63	__webpack_require__(326);
64	__webpack_require__(329);
65	__webpack_require__(330);
66	__webpack_require__(279);
67	__webpack_require__(271);
68	__webpack_require__(269);
69	__webpack_require__(274);
70	__webpack_require__(291);
71	__webpack_require__(331);
72	__webpack_require__(299);
73
74
75/***/ }),
76
77/***/ 269:
78/***/ (function(module, exports, __webpack_require__) {
79
80	var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
81	 * jQuery Cookie Plugin v1.4.0
82	 * https://github.com/carhartl/jquery-cookie
83	 *
84	 * Copyright 2013 Klaus Hartl
85	 * Released under the MIT license
86	 */
87	(function (factory) {
88		if (true) {
89			// AMD. Register as anonymous module.
90			!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(270)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
91		} else {
92			// Browser globals.
93			factory(jQuery);
94		}
95	}(function ($) {
96
97		var pluses = /\+/g;
98
99		function encode(s) {
100			return config.raw ? s : encodeURIComponent(s);
101		}
102
103		function decode(s) {
104			return config.raw ? s : decodeURIComponent(s);
105		}
106
107		function stringifyCookieValue(value) {
108			return encode(config.json ? JSON.stringify(value) : String(value));
109		}
110
111		function parseCookieValue(s) {
112			if (s.indexOf('"') === 0) {
113				// This is a quoted cookie as according to RFC2068, unescape...
114				s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
115			}
116
117			try {
118				// Replace server-side written pluses with spaces.
119				// If we can't decode the cookie, ignore it, it's unusable.
120				s = decodeURIComponent(s.replace(pluses, ' '));
121			} catch(e) {
122				return;
123			}
124
125			try {
126				// If we can't parse the cookie, ignore it, it's unusable.
127				return config.json ? JSON.parse(s) : s;
128			} catch(e) {}
129		}
130
131		function read(s, converter) {
132			var value = config.raw ? s : parseCookieValue(s);
133			return $.isFunction(converter) ? converter(value) : value;
134		}
135
136		var config = $.cookie = function (key, value, options) {
137
138			// Write
139			if (value !== undefined && !$.isFunction(value)) {
140				options = $.extend({}, config.defaults, options);
141
142				if (typeof options.expires === 'number') {
143					var days = options.expires, t = options.expires = new Date();
144					t.setDate(t.getDate() + days);
145				}
146
147				return (document.cookie = [
148					encode(key), '=', stringifyCookieValue(value),
149					options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
150					options.path    ? '; path=' + options.path : '',
151					options.domain  ? '; domain=' + options.domain : '',
152					options.secure  ? '; secure' : ''
153				].join(''));
154			}
155
156			// Read
157
158			var result = key ? undefined : {};
159
160			// To prevent the for loop in the first place assign an empty array
161			// in case there are no cookies at all. Also prevents odd result when
162			// calling $.cookie().
163			var cookies = document.cookie ? document.cookie.split('; ') : [];
164
165			for (var i = 0, l = cookies.length; i < l; i++) {
166				var parts = cookies[i].split('=');
167				var name = decode(parts.shift());
168				var cookie = parts.join('=');
169
170				if (key && key === name) {
171					// If second argument (value) is a function it's a converter...
172					result = read(cookie, value);
173					break;
174				}
175
176				// Prevent storing a cookie that we couldn't decode.
177				if (!key && (cookie = read(cookie)) !== undefined) {
178					result[name] = cookie;
179				}
180			}
181
182			return result;
183		};
184
185		config.defaults = {};
186
187		$.removeCookie = function (key, options) {
188			if ($.cookie(key) === undefined) {
189				return false;
190			}
191
192			// Must not alter options, thus extending a fresh object...
193			$.cookie(key, '', $.extend({}, options, { expires: -1 }));
194			return !$.cookie(key);
195		};
196
197	}));
198
199
200/***/ }),
201
202/***/ 270:
203/***/ (function(module, exports) {
204
205	module.exports = jQuery;
206
207/***/ }),
208
209/***/ 271:
210/***/ (function(module, exports) {
211
212	/*!
213	 * jQuery Validation Plugin 1.11.1
214	 *
215	 * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
216	 * http://docs.jquery.com/Plugins/Validation
217	 *
218	 * Copyright 2013 Jörn Zaefferer
219	 * Released under the MIT license:
220	 *   http://www.opensource.org/licenses/mit-license.php
221	 */
222
223	(function($) {
224
225	$.extend($.fn, {
226		// http://docs.jquery.com/Plugins/Validation/validate
227		validate: function( options ) {
228
229			// if nothing is selected, return nothing; can't chain anyway
230			if ( !this.length ) {
231				if ( options && options.debug && window.console ) {
232					console.warn( "Nothing selected, can't validate, returning nothing." );
233				}
234				return;
235			}
236
237			// check if a validator for this form was already created
238			var validator = $.data( this[0], "validator" );
239			if ( validator ) {
240				return validator;
241			}
242
243			// Add novalidate tag if HTML5.
244			this.attr( "novalidate", "novalidate" );
245
246			validator = new $.validator( options, this[0] );
247			$.data( this[0], "validator", validator );
248
249			if ( validator.settings.onsubmit ) {
250
251				this.validateDelegate( ":submit", "click", function( event ) {
252					if ( validator.settings.submitHandler ) {
253						validator.submitButton = event.target;
254					}
255					// allow suppressing validation by adding a cancel class to the submit button
256					if ( $(event.target).hasClass("cancel") ) {
257						validator.cancelSubmit = true;
258					}
259
260					// allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
261					if ( $(event.target).attr("formnovalidate") !== undefined ) {
262						validator.cancelSubmit = true;
263					}
264				});
265
266				// validate the form on submit
267				this.submit( function( event ) {
268					if ( validator.settings.debug ) {
269						// prevent form submit to be able to see console output
270						event.preventDefault();
271					}
272					function handle() {
273						var hidden;
274						if ( validator.settings.submitHandler ) {
275							if ( validator.submitButton ) {
276								// insert a hidden input as a replacement for the missing submit button
277								hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val( $(validator.submitButton).val() ).appendTo(validator.currentForm);
278							}
279							validator.settings.submitHandler.call( validator, validator.currentForm, event );
280							if ( validator.submitButton ) {
281								// and clean up afterwards; thanks to no-block-scope, hidden can be referenced
282								hidden.remove();
283							}
284							return false;
285						}
286						return true;
287					}
288
289					// prevent submit for invalid forms or custom submit handlers
290					if ( validator.cancelSubmit ) {
291						validator.cancelSubmit = false;
292						return handle();
293					}
294					if ( validator.form() ) {
295						if ( validator.pendingRequest ) {
296							validator.formSubmitted = true;
297							return false;
298						}
299						return handle();
300					} else {
301						validator.focusInvalid();
302						return false;
303					}
304				});
305			}
306
307			return validator;
308		},
309		// http://docs.jquery.com/Plugins/Validation/valid
310		valid: function() {
311			if ( $(this[0]).is("form")) {
312				return this.validate().form();
313			} else {
314				var valid = true;
315				var validator = $(this[0].form).validate();
316				this.each(function() {
317					valid = valid && validator.element(this);
318				});
319				return valid;
320			}
321		},
322		// attributes: space seperated list of attributes to retrieve and remove
323		removeAttrs: function( attributes ) {
324			var result = {},
325				$element = this;
326			$.each(attributes.split(/\s/), function( index, value ) {
327				result[value] = $element.attr(value);
328				$element.removeAttr(value);
329			});
330			return result;
331		},
332		// http://docs.jquery.com/Plugins/Validation/rules
333		rules: function( command, argument ) {
334			var element = this[0];
335
336			if ( command ) {
337				var settings = $.data(element.form, "validator").settings;
338				var staticRules = settings.rules;
339				var existingRules = $.validator.staticRules(element);
340				switch(command) {
341				case "add":
342					$.extend(existingRules, $.validator.normalizeRule(argument));
343					// remove messages from rules, but allow them to be set separetely
344					delete existingRules.messages;
345					staticRules[element.name] = existingRules;
346					if ( argument.messages ) {
347						settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
348					}
349					break;
350				case "remove":
351					if ( !argument ) {
352						delete staticRules[element.name];
353						return existingRules;
354					}
355					var filtered = {};
356					$.each(argument.split(/\s/), function( index, method ) {
357						filtered[method] = existingRules[method];
358						delete existingRules[method];
359					});
360					return filtered;
361				}
362			}
363
364			var data = $.validator.normalizeRules(
365			$.extend(
366				{},
367				$.validator.classRules(element),
368				$.validator.attributeRules(element),
369				$.validator.dataRules(element),
370				$.validator.staticRules(element)
371			), element);
372
373			// make sure required is at front
374			if ( data.required ) {
375				var param = data.required;
376				delete data.required;
377				data = $.extend({required: param}, data);
378			}
379
380			return data;
381		}
382	});
383
384	// Custom selectors
385	$.extend($.expr[":"], {
386		// http://docs.jquery.com/Plugins/Validation/blank
387		blank: function( a ) { return !$.trim("" + $(a).val()); },
388		// http://docs.jquery.com/Plugins/Validation/filled
389		filled: function( a ) { return !!$.trim("" + $(a).val()); },
390		// http://docs.jquery.com/Plugins/Validation/unchecked
391		unchecked: function( a ) { return !$(a).prop("checked"); }
392	});
393
394	// constructor for validator
395	$.validator = function( options, form ) {
396		this.settings = $.extend( true, {}, $.validator.defaults, options );
397		this.currentForm = form;
398		this.init();
399	};
400
401	$.validator.format = function( source, params ) {
402		if ( arguments.length === 1 ) {
403			return function() {
404				var args = $.makeArray(arguments);
405				args.unshift(source);
406				return $.validator.format.apply( this, args );
407			};
408		}
409		if ( arguments.length > 2 && params.constructor !== Array  ) {
410			params = $.makeArray(arguments).slice(1);
411		}
412		if ( params.constructor !== Array ) {
413			params = [ params ];
414		}
415		$.each(params, function( i, n ) {
416			source = source.replace( new RegExp("\\{" + i + "\\}", "g"), function() {
417				return n;
418			});
419		});
420		return source;
421	};
422
423	$.extend($.validator, {
424
425		defaults: {
426			messages: {},
427			groups: {},
428			rules: {},
429			errorClass: "error",
430			validClass: "valid",
431			errorElement: "label",
432			focusInvalid: true,
433			errorContainer: $([]),
434			errorLabelContainer: $([]),
435			onsubmit: true,
436			ignore: ":hidden",
437			ignoreTitle: false,
438			onfocusin: function( element, event ) {
439				this.lastActive = element;
440
441				// hide error label and remove error class on focus if enabled
442				if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
443					if ( this.settings.unhighlight ) {
444						this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
445					}
446					this.addWrapper(this.errorsFor(element)).hide();
447				}
448			},
449			onfocusout: function( element, event ) {
450				if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
451					this.element(element);
452				}
453			},
454			onkeyup: function( element, event ) {
455				if ( event.which === 9 && this.elementValue(element) === "" ) {
456					return;
457				} else if ( element.name in this.submitted || element === this.lastElement ) {
458					this.element(element);
459				}
460			},
461			onclick: function( element, event ) {
462				// click on selects, radiobuttons and checkboxes
463				if ( element.name in this.submitted ) {
464					this.element(element);
465				}
466				// or option elements, check parent select in that case
467				else if ( element.parentNode.name in this.submitted ) {
468					this.element(element.parentNode);
469				}
470			},
471			highlight: function( element, errorClass, validClass ) {
472				if ( element.type === "radio" ) {
473					this.findByName(element.name).addClass(errorClass).removeClass(validClass);
474				} else {
475					$(element).addClass(errorClass).removeClass(validClass);
476				}
477			},
478			unhighlight: function( element, errorClass, validClass ) {
479				if ( element.type === "radio" ) {
480					this.findByName(element.name).removeClass(errorClass).addClass(validClass);
481				} else {
482					$(element).removeClass(errorClass).addClass(validClass);
483				}
484			}
485		},
486
487		// http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
488		setDefaults: function( settings ) {
489			$.extend( $.validator.defaults, settings );
490		},
491
492		messages: {
493			required: "This field is required.",
494			remote: "Please fix this field.",
495			email: "Please enter a valid email address.",
496			url: "Please enter a valid URL.",
497			date: "Please enter a valid date.",
498			dateISO: "Please enter a valid date (ISO).",
499			number: "Please enter a valid number.",
500			digits: "Please enter only digits.",
501			creditcard: "Please enter a valid credit card number.",
502			equalTo: "Please enter the same value again.",
503			maxlength: $.validator.format("Please enter no more than {0} characters."),
504			minlength: $.validator.format("Please enter at least {0} characters."),
505			rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
506			range: $.validator.format("Please enter a value between {0} and {1}."),
507			max: $.validator.format("Please enter a value less than or equal to {0}."),
508			min: $.validator.format("Please enter a value greater than or equal to {0}.")
509		},
510
511		autoCreateRanges: false,
512
513		prototype: {
514
515			init: function() {
516				this.labelContainer = $(this.settings.errorLabelContainer);
517				this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
518				this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
519				this.submitted = {};
520				this.valueCache = {};
521				this.pendingRequest = 0;
522				this.pending = {};
523				this.invalid = {};
524				this.reset();
525
526				var groups = (this.groups = {});
527				$.each(this.settings.groups, function( key, value ) {
528					if ( typeof value === "string" ) {
529						value = value.split(/\s/);
530					}
531					$.each(value, function( index, name ) {
532						groups[name] = key;
533					});
534				});
535				var rules = this.settings.rules;
536				$.each(rules, function( key, value ) {
537					rules[key] = $.validator.normalizeRule(value);
538				});
539
540				function delegate(event) {
541					var validator = $.data(this[0].form, "validator"),
542						eventType = "on" + event.type.replace(/^validate/, "");
543					if ( validator.settings[eventType] ) {
544						validator.settings[eventType].call(validator, this[0], event);
545					}
546				}
547				$(this.currentForm)
548					.validateDelegate(":text, [type='password'], [type='file'], select, textarea, " +
549						"[type='number'], [type='search'] ,[type='tel'], [type='url'], " +
550						"[type='email'], [type='datetime'], [type='date'], [type='month'], " +
551						"[type='week'], [type='time'], [type='datetime-local'], " +
552						"[type='range'], [type='color'] ",
553						"focusin focusout keyup", delegate)
554					.validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate);
555
556				if ( this.settings.invalidHandler ) {
557					$(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
558				}
559			},
560
561			// http://docs.jquery.com/Plugins/Validation/Validator/form
562			form: function() {
563				this.checkForm();
564				$.extend(this.submitted, this.errorMap);
565				this.invalid = $.extend({}, this.errorMap);
566				if ( !this.valid() ) {
567					$(this.currentForm).triggerHandler("invalid-form", [this]);
568				}
569				this.showErrors();
570				return this.valid();
571			},
572
573			checkForm: function() {
574				this.prepareForm();
575				for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
576					this.check( elements[i] );
577				}
578				return this.valid();
579			},
580
581			// http://docs.jquery.com/Plugins/Validation/Validator/element
582			element: function( element ) {
583				element = this.validationTargetFor( this.clean( element ) );
584				this.lastElement = element;
585				this.prepareElement( element );
586				this.currentElements = $(element);
587				var result = this.check( element ) !== false;
588				if ( result ) {
589					delete this.invalid[element.name];
590				} else {
591					this.invalid[element.name] = true;
592				}
593				if ( !this.numberOfInvalids() ) {
594					// Hide error containers on last error
595					this.toHide = this.toHide.add( this.containers );
596				}
597				this.showErrors();
598				return result;
599			},
600
601			// http://docs.jquery.com/Plugins/Validation/Validator/showErrors
602			showErrors: function( errors ) {
603				if ( errors ) {
604					// add items to error list and map
605					$.extend( this.errorMap, errors );
606					this.errorList = [];
607					for ( var name in errors ) {
608						this.errorList.push({
609							message: errors[name],
610							element: this.findByName(name)[0]
611						});
612					}
613					// remove items from success list
614					this.successList = $.grep( this.successList, function( element ) {
615						return !(element.name in errors);
616					});
617				}
618				if ( this.settings.showErrors ) {
619					this.settings.showErrors.call( this, this.errorMap, this.errorList );
620				} else {
621					this.defaultShowErrors();
622				}
623			},
624
625			// http://docs.jquery.com/Plugins/Validation/Validator/resetForm
626			resetForm: function() {
627				if ( $.fn.resetForm ) {
628					$(this.currentForm).resetForm();
629				}
630				this.submitted = {};
631				this.lastElement = null;
632				this.prepareForm();
633				this.hideErrors();
634				this.elements().removeClass( this.settings.errorClass ).removeData( "previousValue" );
635			},
636
637			numberOfInvalids: function() {
638				return this.objectLength(this.invalid);
639			},
640
641			objectLength: function( obj ) {
642				var count = 0;
643				for ( var i in obj ) {
644					count++;
645				}
646				return count;
647			},
648
649			hideErrors: function() {
650				this.addWrapper( this.toHide ).hide();
651			},
652
653			valid: function() {
654				return this.size() === 0;
655			},
656
657			size: function() {
658				return this.errorList.length;
659			},
660
661			focusInvalid: function() {
662				if ( this.settings.focusInvalid ) {
663					try {
664						$(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
665						.filter(":visible")
666						.focus()
667						// manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
668						.trigger("focusin");
669					} catch(e) {
670						// ignore IE throwing errors when focusing hidden elements
671					}
672				}
673			},
674
675			findLastActive: function() {
676				var lastActive = this.lastActive;
677				return lastActive && $.grep(this.errorList, function( n ) {
678					return n.element.name === lastActive.name;
679				}).length === 1 && lastActive;
680			},
681
682			elements: function() {
683				var validator = this,
684					rulesCache = {};
685
686				// select all valid inputs inside the form (no submit or reset buttons)
687				return $(this.currentForm)
688				.find("input, select, textarea")
689				.not(":submit, :reset, :image, [disabled]")
690				.not( this.settings.ignore )
691				.filter(function() {
692					if ( !this.name && validator.settings.debug && window.console ) {
693						console.error( "%o has no name assigned", this);
694					}
695
696					// select only the first element for each name, and only those with rules specified
697					if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) {
698						return false;
699					}
700
701					rulesCache[this.name] = true;
702					return true;
703				});
704			},
705
706			clean: function( selector ) {
707				return $(selector)[0];
708			},
709
710			errors: function() {
711				var errorClass = this.settings.errorClass.replace(" ", ".");
712				return $(this.settings.errorElement + "." + errorClass, this.errorContext);
713			},
714
715			reset: function() {
716				this.successList = [];
717				this.errorList = [];
718				this.errorMap = {};
719				this.toShow = $([]);
720				this.toHide = $([]);
721				this.currentElements = $([]);
722			},
723
724			prepareForm: function() {
725				this.reset();
726				this.toHide = this.errors().add( this.containers );
727			},
728
729			prepareElement: function( element ) {
730				this.reset();
731				this.toHide = this.errorsFor(element);
732			},
733
734			elementValue: function( element ) {
735				var type = $(element).attr("type"),
736					val = $(element).val();
737
738				if ( type === "radio" || type === "checkbox" ) {
739					return $("input[name='" + $(element).attr("name") + "']:checked").val();
740				}
741
742				if ( typeof val === "string" ) {
743					return val.replace(/\r/g, "");
744				}
745				return val;
746			},
747
748			check: function( element ) {
749				element = this.validationTargetFor( this.clean( element ) );
750
751				var rules = $(element).rules();
752				var dependencyMismatch = false;
753				var val = this.elementValue(element);
754				var result;
755
756				for (var method in rules ) {
757					var rule = { method: method, parameters: rules[method] };
758					try {
759
760						result = $.validator.methods[method].call( this, val, element, rule.parameters );
761
762						// if a method indicates that the field is optional and therefore valid,
763						// don't mark it as valid when there are no other rules
764						if ( result === "dependency-mismatch" ) {
765							dependencyMismatch = true;
766							continue;
767						}
768						dependencyMismatch = false;
769
770						if ( result === "pending" ) {
771							this.toHide = this.toHide.not( this.errorsFor(element) );
772							return;
773						}
774
775						if ( !result ) {
776							this.formatAndAdd( element, rule );
777							return false;
778						}
779					} catch(e) {
780						if ( this.settings.debug && window.console ) {
781							console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
782						}
783						throw e;
784					}
785				}
786				if ( dependencyMismatch ) {
787					return;
788				}
789				if ( this.objectLength(rules) ) {
790					this.successList.push(element);
791				}
792				return true;
793			},
794
795			// return the custom message for the given element and validation method
796			// specified in the element's HTML5 data attribute
797			customDataMessage: function( element, method ) {
798				return $(element).data("msg-" + method.toLowerCase()) || (element.attributes && $(element).attr("data-msg-" + method.toLowerCase()));
799			},
800
801			// return the custom message for the given element name and validation method
802			customMessage: function( name, method ) {
803				var m = this.settings.messages[name];
804				return m && (m.constructor === String ? m : m[method]);
805			},
806
807			// return the first defined argument, allowing empty strings
808			findDefined: function() {
809				for(var i = 0; i < arguments.length; i++) {
810					if ( arguments[i] !== undefined ) {
811						return arguments[i];
812					}
813				}
814				return undefined;
815			},
816
817			defaultMessage: function( element, method ) {
818				return this.findDefined(
819					this.customMessage( element.name, method ),
820					this.customDataMessage( element, method ),
821					// title is never undefined, so handle empty string as undefined
822					!this.settings.ignoreTitle && element.title || undefined,
823					$.validator.messages[method],
824					"<strong>Warning: No message defined for " + element.name + "</strong>"
825				);
826			},
827
828			formatAndAdd: function( element, rule ) {
829				var message = this.defaultMessage( element, rule.method ),
830					theregex = /\$?\{(\d+)\}/g;
831				if ( typeof message === "function" ) {
832					message = message.call(this, rule.parameters, element);
833				} else if (theregex.test(message)) {
834					message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters);
835				}
836				this.errorList.push({
837					message: message,
838					element: element
839				});
840
841				this.errorMap[element.name] = message;
842				this.submitted[element.name] = message;
843			},
844
845			addWrapper: function( toToggle ) {
846				if ( this.settings.wrapper ) {
847					toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
848				}
849				return toToggle;
850			},
851
852			defaultShowErrors: function() {
853				var i, elements;
854				for ( i = 0; this.errorList[i]; i++ ) {
855					var error = this.errorList[i];
856					if ( this.settings.highlight ) {
857						this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.val
857idClass );
858					}
859					this.showLabel( error.element, error.message );
860				}
861				if ( this.errorList.length ) {
862					this.toShow = this.toShow.add( this.containers );
863				}
864				if ( this.settings.success ) {
865					for ( i = 0; this.successList[i]; i++ ) {
866						this.showLabel( this.successList[i] );
867					}
868				}
869				if ( this.settings.unhighlight ) {
870					for ( i = 0, elements = this.validElements(); elements[i]; i++ ) {
871						this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
872					}
873				}
874				this.toHide = this.toHide.not( this.toShow );
875				this.hideErrors();
876				this.addWrapper( this.toShow ).show();
877			},
878
879			validElements: function() {
880				return this.currentElements.not(this.invalidElements());
881			},
882
883			invalidElements: function() {
884				return $(this.errorList).map(function() {
885					return this.element;
886				});
887			},
888
889			showLabel: function( element, message ) {
890				var label = this.errorsFor( element );
891				if ( label.length ) {
892					// refresh error/success class
893					label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
894					// replace message on existing label
895					label.html(message);
896				} else {
897					// create label
898					label = $("<" + this.settings.errorElement + ">")
899						.attr("for", this.idOrName(element))
900						.addClass(this.settings.errorClass)
901						.html(message || "");
902					if ( this.settings.wrapper ) {
903						// make sure the element is visible, even in IE
904						// actually showing the wrapped element is handled elsewhere
905						label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
906					}
907					if ( !this.labelContainer.append(label).length ) {
908						if ( this.settings.errorPlacement ) {
909							this.settings.errorPlacement(label, $(element) );
910						} else {
911							label.insertAfter(element);
912						}
913					}
914				}
915				if ( !message && this.settings.success ) {
916					label.text("");
917					if ( typeof this.settings.success === "string" ) {
918						label.addClass( this.settings.success );
919					} else {
920						this.settings.success( label, element );
921					}
922				}
923				this.toShow = this.toShow.add(label);
924			},
925
926			errorsFor: function( element ) {
927				var name = this.idOrName(element);
928				return this.errors().filter(function() {
929					return $(this).attr("for") === name;
930				});
931			},
932
933			idOrName: function( element ) {
934				return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
935			},
936
937			validationTargetFor: function( element ) {
938				// if radio/checkbox, validate first element in group instead
939				if ( this.checkable(element) ) {
940					element = this.findByName( element.name ).not(this.settings.ignore)[0];
941				}
942				return element;
943			},
944
945			checkable: function( element ) {
946				return (/radio|checkbox/i).test(element.type);
947			},
948
949			findByName: function( name ) {
950				return $(this.currentForm).find("[name='" + name + "']");
951			},
952
953			getLength: function( value, element ) {
954				switch( element.nodeName.toLowerCase() ) {
955				case "select":
956					return $("option:selected", element).length;
957				case "input":
958					if ( this.checkable( element) ) {
959						return this.findByName(element.name).filter(":checked").length;
960					}
961				}
962				return value.length;
963			},
964
965			depend: function( param, element ) {
966				return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true;
967			},
968
969			dependTypes: {
970				"boolean": function( param, element ) {
971					return param;
972				},
973				"string": function( param, element ) {
974					return !!$(param, element.form).length;
975				},
976				"function": function( param, element ) {
977					return param(element);
978				}
979			},
980
981			optional: function( element ) {
982				var val = this.elementValue(element);
983				return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch";
984			},
985
986			startRequest: function( element ) {
987				if ( !this.pending[element.name] ) {
988					this.pendingRequest++;
989					this.pending[element.name] = true;
990				}
991			},
992
993			stopRequest: function( element, valid ) {
994				this.pendingRequest--;
995				// sometimes synchronization fails, make sure pendingRequest is never < 0
996				if ( this.pendingRequest < 0 ) {
997					this.pendingRequest = 0;
998				}
999				delete this.pending[element.name];
1000				if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
1001					$(this.currentForm).submit();
1002					this.formSubmitted = false;
1003				} else if (!valid && this.pendingRequest === 0 && this.formSubmitted) {
1004					$(this.currentForm).triggerHandler("invalid-form", [this]);
1005					this.formSubmitted = false;
1006				}
1007			},
1008
1009			previousValue: function( element ) {
1010				return $.data(element, "previousValue") || $.data(element, "previousValue", {
1011					old: null,
1012					valid: true,
1013					message: this.defaultMessage( element, "remote" )
1014				});
1015			}
1016
1017		},
1018
1019		classRuleSettings: {
1020			required: {required: true},
1021			email: {email: true},
1022			url: {url: true},
1023			date: {date: true},
1024			dateISO: {dateISO: true},
1025			number: {number: true},
1026			digits: {digits: true},
1027			creditcard: {creditcard: true}
1028		},
1029
1030		addClassRules: function( className, rules ) {
1031			if ( className.constructor === String ) {
1032				this.classRuleSettings[className] = rules;
1033			} else {
1034				$.extend(this.classRuleSettings, className);
1035			}
1036		},
1037
1038		classRules: function( element ) {
1039			var rules = {};
1040			var classes = $(element).attr("class");
1041			if ( classes ) {
1042				$.each(classes.split(" "), function() {
1043					if ( this in $.validator.classRuleSettings ) {
1044						$.extend(rules, $.validator.classRuleSettings[this]);
1045					}
1046				});
1047			}
1048			return rules;
1049		},
1050
1051		attributeRules: function( element ) {
1052			var rules = {};
1053			var $element = $(element);
1054			var type = $element[0].getAttribute("type");
1055
1056			for (var method in $.validator.methods) {
1057				var value;
1058
1059				// support for <input required> in both html5 and older browsers
1060				if ( method === "required" ) {
1061					value = $element.get(0).getAttribute(method);
1062					// Some browsers return an empty string for the required attribute
1063					// and non-HTML5 browsers might have required="" markup
1064					if ( value === "" ) {
1065						value = true;
1066					}
1067					// force non-HTML5 browsers to return bool
1068					value = !!value;
1069				} else {
1070					value = $element.attr(method);
1071				}
1072
1073				// convert the value to a number for number inputs, and for text for backwards compability
1074				// allows type="date" and others to be compared as strings
1075				if ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
1076					value = Number(value);
1077				}
1078
1079				if ( value ) {
1080					rules[method] = value;
1081				} else if ( type === method && type !== 'range' ) {
1082					// exception: the jquery validate 'range' method
1083					// does not test for the html5 'range' type
1084					rules[method] = true;
1085				}
1086			}
1087
1088			// maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
1089			if ( rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength) ) {
1090				delete rules.maxlength;
1091			}
1092
1093			return rules;
1094		},
1095
1096		dataRules: function( element ) {
1097			var method, value,
1098				rules = {}, $element = $(element);
1099			for (method in $.validator.methods) {
1100				value = $element.data("rule-" + method.toLowerCase());
1101				if ( value !== undefined ) {
1102					rules[method] = value;
1103				}
1104			}
1105			return rules;
1106		},
1107
1108		staticRules: function( element ) {
1109			var rules = {};
1110			var validator = $.data(element.form, "validator");
1111			if ( validator.settings.rules ) {
1112				rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
1113			}
1114			return rules;
1115		},
1116
1117		normalizeRules: function( rules, element ) {
1118			// handle dependency check
1119			$.each(rules, function( prop, val ) {
1120				// ignore rule when param is explicitly false, eg. required:false
1121				if ( val === false ) {
1122					delete rules[prop];
1123					return;
1124				}
1125				if ( val.param || val.depends ) {
1126					var keepRule = true;
1127					switch (typeof val.depends) {
1128					case "string":
1129						keepRule = !!$(val.depends, element.form).length;
1130						break;
1131					case "function":
1132						keepRule = val.depends.call(element, element);
1133						break;
1134					}
1135					if ( keepRule ) {
1136						rules[prop] = val.param !== undefined ? val.param : true;
1137					} else {
1138						delete rules[prop];
1139					}
1140				}
1141			});
1142
1143			// evaluate parameters
1144			$.each(rules, function( rule, parameter ) {
1145				rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
1146			});
1147
1148			// clean number parameters
1149			$.each(['minlength', 'maxlength'], function() {
1150				if ( rules[this] ) {
1151					rules[this] = Number(rules[this]);
1152				}
1153			});
1154			$.each(['rangelength', 'range'], function() {
1155				var parts;
1156				if ( rules[this] ) {
1157					if ( $.isArray(rules[this]) ) {
1158						rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
1159					} else if ( typeof rules[this] === "string" ) {
1160						parts = rules[this].split(/[\s,]+/);
1161						rules[this] = [Number(parts[0]), Number(parts[1])];
1162					}
1163				}
1164			});
1165
1166			if ( $.validator.autoCreateRanges ) {
1167				// auto-create ranges
1168				if ( rules.min && rules.max ) {
1169					rules.range = [rules.min, rules.max];
1170					delete rules.min;
1171					delete rules.max;
1172				}
1173				if ( rules.minlength && rules.maxlength ) {
1174					rules.rangelength = [rules.minlength, rules.maxlength];
1175					delete rules.minlength;
1176					delete rules.maxlength;
1177				}
1178			}
1179
1180			return rules;
1181		},
1182
vendor: 4,967 bytes, lines 1183-1263
1183		// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
1184		normalizeRule: function( data ) {
1185			if ( typeof data === "string" ) {
1186				var transformed = {};
1187				$.each(data.split(/\s/), function() {
1188					transformed[this] = true;
1189				});
1190				data = transformed;
1191			}
1192			return data;
1193		},
1194
1195		// http://docs.jquery.com/Plugins/Validation/Validator/addMethod
1196		addMethod: function( name, method, message ) {
1197			$.validator.methods[name] = method;
1198			$.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];
1199			if ( method.length < 3 ) {
1200				$.validator.addClassRules(name, $.validator.normalizeRule(name));
1201			}
1202		},
1203
1204		methods: {
1205
1206			// http://docs.jquery.com/Plugins/Validation/Methods/required
1207			required: function( value, element, param ) {
1208				// check if dependency is met
1209				if ( !this.depend(param, element) ) {
1210					return "dependency-mismatch";
1211				}
1212				if ( element.nodeName.toLowerCase() === "select" ) {
1213					// could be an array for select-multiple or a string, both are fine this way
1214					var val = $(element).val();
1215					return val && val.length > 0;
1216				}
1217				if ( this.checkable(element) ) {
1218					return this.getLength(value, element) > 0;
1219				}
1220				return $.trim(value).length > 0;
1221			},
1222
1223			// http://docs.jquery.com/Plugins/Validation/Methods/email
1224			email: function( value, element ) {
1225				// contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
1226				return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(value);
1227			},
1228
1229			// http://docs.jquery.com/Plugins/Validation/Methods/url
1230			url: function( value, element ) {
1231				// contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
1232				return this.optional(element) || /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
1233			},
1234
1235			// http://docs.jquery.com/Plugins/Validation/Methods/date
1236			date: function( value, element ) {
1237				return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString());
1238			},
1239
1240			// http://docs.jquery.com/Plugins/Validation/Methods/dateISO
1241			dateISO: function( value, element ) {
1242				return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value);
1243			},
1244
1245			// http://docs.jquery.com/Plugins/Validation/Methods/number
1246			number: function( value, element ) {
1247				return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
1248			},
1249
1250			// http://docs.jquery.com/Plugins/Validation/Methods/digits
1251			digits: function( value, element ) {
1252				return this.optional(element) || /^\d+$/.test(value);
1253			},
1254
1255			// http://docs.jquery.com/Plugins/Validation/Methods/creditcard
1256			// based on http://en.wikipedia.org/wiki/Luhn
1257			creditcard: function( value, element ) {
1258				if ( this.optional(element) ) {
1259					return "dependency-mismatch";
1260				}
1261				// accept only spaces, digits and dashes
1262				if ( /[^0-9 \-]+/.test(value) ) {
1263					return false;
1264				}
1265				var nCheck = 0,
1266					nDigit = 0,
1267					bEven = false;
1268
1269				value = value.replace(/\D/g, "");
1270
1271				for (var n = value.length - 1; n >= 0; n--) {
1272					var cDigit = value.charAt(n);
1273					nDigit = parseInt(cDigit, 10);
1274					if ( bEven ) {
1275						if ( (nDigit *= 2) > 9 ) {
1276							nDigit -= 9;
1277						}
1278					}
1279					nCheck += nDigit;
1280					bEven = !bEven;
1281				}
1282
1283				return (nCheck % 10) === 0;
1284			},
1285
1286			// http://docs.jquery.com/Plugins/Validation/Methods/minlength
1287			minlength: function( value, element, param ) {
1288				var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1289				return this.optional(element) || length >= param;
1290			},
1291
1292			// http://docs.jquery.com/Plugins/Validation/Methods/maxlength
1293			maxlength: function( value, element, param ) {
1294				var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1295				return this.optional(element) || length <= param;
1296			},
1297
1298			// http://docs.jquery.com/Plugins/Validation/Methods/rangelength
1299			rangelength: function( value, element, param ) {
1300				var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1301				return this.optional(element) || ( length >= param[0] && length <= param[1] );
1302			},
1303
1304			// http://docs.jquery.com/Plugins/Validation/Methods/min
1305			min: function( value, element, param ) {
1306				return this.optional(element) || value >= param;
1307			},
1308
1309			// http://docs.jquery.com/Plugins/Validation/Methods/max
1310			max: function( value, element, param ) {
1311				return this.optional(element) || value <= param;
1312			},
1313
1314			// http://docs.jquery.com/Plugins/Validation/Methods/range
1315			range: function( value, element, param ) {
1316				return this.optional(element) || ( value >= param[0] && value <= param[1] );
1317			},
1318
1319			// http://docs.jquery.com/Plugins/Validation/Methods/equalTo
1320			equalTo: function( value, element, param ) {
1321				// bind to the blur event of the target in order to revalidate whenever the target field is updated
1322				// TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
1323				var target = $(param);
1324				if ( this.settings.onfocusout ) {
1325					target.unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
1326						$(element).valid();
1327					});
1328				}
1329				return value === target.val();
1330			},
1331
1332			// http://docs.jquery.com/Plugins/Validation/Methods/remote
1333			remote: function( value, element, param ) {
1334				if ( this.optional(element) ) {
1335					return "dependency-mismatch";
1336				}
1337
1338				var previous = this.previousValue(element);
1339				if (!this.settings.messages[element.name] ) {
1340					this.settings.messages[element.name] = {};
1341				}
1342				previous.originalMessage = this.settings.messages[element.name].remote;
1343				this.settings.messages[element.name].remote = previous.message;
1344
1345				param = typeof param === "string" && {url:param} || param;
1346
1347				if ( previous.old === value ) {
1348					return previous.valid;
1349				}
1350
1351				previous.old = value;
1352				var validator = this;
1353				this.startRequest(element);
1354				var data = {};
1355				data[element.name] = value;
1356				$.ajax($.extend(true, {
1357					url: param,
1358					mode: "abort",
1359					port: "validate" + element.name,
1360					dataType: "json",
1361					data: data,
1362					success: function( response ) {
1363						validator.settings.messages[element.name].remote = previous.originalMessage;
1364						var valid = response === true || response === "true";
1365						if ( valid ) {
1366							var submitted = validator.formSubmitted;
1367							validator.prepareElement(element);
1368							validator.formSubmitted = submitted;
1369							validator.successList.push(element);
1370							delete validator.invalid[element.name];
1371							validator.showErrors();
1372						} else {
1373							var errors = {};
1374							var message = response || validator.defaultMessage( element, "remote" );
1375							errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
1376							validator.invalid[element.name] = true;
1377							validator.showErrors(errors);
1378						}
1379						previous.valid = valid;
1380						validator.stopRequest(element, valid);
1381					}
1382				}, param));
1383				return "pending";
1384			}
1385
1386		}
1387
1388	});
1389
1390	// deprecated, use $.validator.format instead
1391	$.format = $.validator.format;
1392
1393	}(jQuery));
1394
1395	// ajax mode: abort
1396	// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
1397	// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
1398	(function($) {
1399		var pendingRequests = {};
1400		// Use a prefilter if available (1.5+)
1401		if ( $.ajaxPrefilter ) {
1402			$.ajaxPrefilter(function( settings, _, xhr ) {
1403				var port = settings.port;
1404				if ( settings.mode === "abort" ) {
1405					if ( pendingRequests[port] ) {
1406						pendingRequests[port].abort();
1407					}
1408					pendingRequests[port] = xhr;
1409				}
1410			});
1411		} else {
1412			// Proxy ajax
1413			var ajax = $.ajax;
1414			$.ajax = function( settings ) {
1415				var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
1416					port = ( "port" in settings ? settings : $.ajaxSettings ).port;
1417				if ( mode === "abort" ) {
1418					if ( pendingRequests[port] ) {
1419						pendingRequests[port].abort();
1420					}
1421					pendingRequests[port] = ajax.apply(this, arguments);
1422					return pendingRequests[port];
1423				}
1424				return ajax.apply(this, arguments);
1425			};
1426		}
1427	}(jQuery));
1428
1429	// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
1430	// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
1431	(function($) {
1432		$.extend($.fn, {
1433			validateDelegate: function( delegate, type, handler ) {
1434				return this.bind(type, function( event ) {
1435					var target = $(event.target);
1436					if ( target.is(delegate) ) {
1437						return handler.apply(target, arguments);
1438					}
1439				});
1440			}
1441		});
1442	}(jQuery));
1443
1444
1445/***/ }),
1446
1447/***/ 273:
1448/***/ (function(module, exports) {
1449
1450	/* ========================================================================
1451	 * Bootstrap: modal.js v3.3.7
1452	 * http://getbootstrap.com/javascript/#modals
1453	 * ========================================================================
1454	 * Copyright 2011-2016 Twitter, Inc.
1455	 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1456	 * ======================================================================== */
1457
1458
1459	+function ($) {
1460	  'use strict';
1461
1462	  // MODAL CLASS DEFINITION
1463	  // ======================
1464
1465	  var Modal = function (element, options) {
1466	    this.options             = options
1467	    this.$body               = $(document.body)
1468	    this.$element            = $(element)
1469	    this.$dialog             = this.$element.find('.modal-dialog')
1470	    this.$backdrop           = null
1471	    this.isShown             = null
1472	    this.originalBodyPad     = null
1473	    this.scrollbarWidth      = 0
1474	    this.ignoreBackdropClick = false
1475
1476	    if (this.options.remote) {
1477	      this.$element
1478	        .find('.modal-content')
1479	        .load(this.options.remote, $.proxy(function () {
1480	          this.$element.trigger('loaded.bs.modal')
1481	        }, this))
1482	    }
1483	  }
1484
1485	  Modal.VERSION  = '3.3.7'
1486
1487	  Modal.TRANSITION_DURATION = 300
1488	  Modal.BACKDROP_TRANSITION_DURATION = 150
1489
1490	  Modal.DEFAULTS = {
1491	    backdrop: true,
1492	    keyboard: true,
1493	    show: true
1494	  }
1495
1496	  Modal.prototype.toggle = function (_relatedTarget) {
1497	    return this.isShown ? this.hide() : this.show(_relatedTarget)
1498	  }
1499
1500	  Modal.prototype.show = function (_relatedTarget) {
1501	    var that = this
1502	    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
1503
1504	    this.$element.trigger(e)
1505
1506	    if (this.isShown || e.isDefaultPrevented()) return
1507
1508	    this.isShown = true
1509
1510	    this.checkScrollbar()
1511	    this.setScrollbar()
1512	    this.$body.addClass('modal-open')
1513
1514	    this.escape()
1515	    this.resize()
1516
1517	    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
1518
1519	    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
1520	      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
1521	        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
1522	      })
1523	    })
1524
1525	    this.backdrop(function () {
1526	      var transition = $.support.transition && that.$element.hasClass('fade')
1527
1528	      if (!that.$element.parent().length) {
1529	        that.$element.appendTo(that.$body) // don't move modals dom position
1530	      }
1531
1532	      that.$element
1533	        .show()
1534	        .scrollTop(0)
1535
1536	      that.adjustDialog()
1537
1538	      if (transition) {
1539	        that.$element[0].offsetWidth // force reflow
1540	      }
1541
1542	      that.$element.addClass('in')
1543
1544	      that.enforceFocus()
1545
1546	      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
1547
1548	      transition ?
1549	        that.$dialog // wait for modal to slide in
1550	          .one('bsTransitionEnd', function () {
1551	            that.$element.trigger('focus').trigger(e)
1552	          })
1553	          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
1554	        that.$element.trigger('focus').trigger(e)
1555	    })
1556	  }
1557
1558	  Modal.prototype.hide = function (e) {
1559	    if (e) e.preventDefault()
1560
1561	    e = $.Event('hide.bs.modal')
1562
1563	    this.$element.trigger(e)
1564
1565	    if (!this.isShown || e.isDefaultPrevented()) return
1566
1567	    this.isShown = false
1568
1569	    this.escape()
1570	    this.resize()
1571
1572	    $(document).off('focusin.bs.modal')
1573
1574	    this.$element
1575	      .removeClass('in')
1576	      .off('click.dismiss.bs.modal')
1577	      .off('mouseup.dismiss.bs.modal')
1578
1579	    this.$dialog.off('mousedown.dismiss.bs.modal')
1580
1581	    $.support.transition && this.$element.hasClass('fade') ?
1582	      this.$element
1583	        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
1584	        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
1585	      this.hideModal()
1586	  }
1587
1588	  Modal.prototype.enforceFocus = function () {
1589	    $(document)
1590	      .off('focusin.bs.modal') // guard against infinite focus loop
1591	      .on('focusin.bs.modal', $.proxy(function (e) {
1592	        if (document !== e.target &&
1593	            this.$element[0] !== e.target &&
1594	            !this.$element.has(e.target).length) {
1595	          this.$element.trigger('focus')
1596	        }
1597	      }, this))
1598	  }
1599
1600	  Modal.prototype.escape = function () {
1601	    if (this.isShown && this.options.keyboard) {
1602	      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
vendor: 5,872 bytes, lines 1603-1793
1603	        e.which == 27 && this.hide()
1604	      }, this))
1605	    } else if (!this.isShown) {
1606	      this.$element.off('keydown.dismiss.bs.modal')
1607	    }
1608	  }
1609
1610	  Modal.prototype.resize = function () {
1611	    if (this.isShown) {
1612	      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
1613	    } else {
1614	      $(window).off('resize.bs.modal')
1615	    }
1616	  }
1617
1618	  Modal.prototype.hideModal = function () {
1619	    var that = this
1620	    this.$element.hide()
1621	    this.backdrop(function () {
1622	      that.$body.removeClass('modal-open')
1623	      that.resetAdjustments()
1624	      that.resetScrollbar()
1625	      that.$element.trigger('hidden.bs.modal')
1626	    })
1627	  }
1628
1629	  Modal.prototype.removeBackdrop = function () {
1630	    this.$backdrop && this.$backdrop.remove()
1631	    this.$backdrop = null
1632	  }
1633
1634	  Modal.prototype.backdrop = function (callback) {
1635	    var that = this
1636	    var animate = this.$element.hasClass('fade') ? 'fade' : ''
1637
1638	    if (this.isShown && this.options.backdrop) {
1639	      var doAnimate = $.support.transition && animate
1640
1641	      this.$backdrop = $(document.createElement('div'))
1642	        .addClass('modal-backdrop ' + animate)
1643	        .appendTo(this.$body)
1644
1645	      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
1646	        if (this.ignoreBackdropClick) {
1647	          this.ignoreBackdropClick = false
1648	          return
1649	        }
1650	        if (e.target !== e.currentTarget) return
1651	        this.options.backdrop == 'static'
1652	          ? this.$element[0].focus()
1653	          : this.hide()
1654	      }, this))
1655
1656	      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
1657
1658	      this.$backdrop.addClass('in')
1659
1660	      if (!callback) return
1661
1662	      doAnimate ?
1663	        this.$backdrop
1664	          .one('bsTransitionEnd', callback)
1665	          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
1666	        callback()
1667
1668	    } else if (!this.isShown && this.$backdrop) {
1669	      this.$backdrop.removeClass('in')
1670
1671	      var callbackRemove = function () {
1672	        that.removeBackdrop()
1673	        callback && callback()
1674	      }
1675	      $.support.transition && this.$element.hasClass('fade') ?
1676	        this.$backdrop
1677	          .one('bsTransitionEnd', callbackRemove)
1678	          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
1679	        callbackRemove()
1680
1681	    } else if (callback) {
1682	      callback()
1683	    }
1684	  }
1685
1686	  // these following methods are used to handle overflowing modals
1687
1688	  Modal.prototype.handleUpdate = function () {
1689	    this.adjustDialog()
1690	  }
1691
1692	  Modal.prototype.adjustDialog = function () {
1693	    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
1694
1695	    this.$element.css({
1696	      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
1697	      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
1698	    })
1699	  }
1700
1701	  Modal.prototype.resetAdjustments = function () {
1702	    this.$element.css({
1703	      paddingLeft: '',
1704	      paddingRight: ''
1705	    })
1706	  }
1707
1708	  Modal.prototype.checkScrollbar = function () {
1709	    var fullWindowWidth = window.innerWidth
1710	    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
1711	      var documentElementRect = document.documentElement.getBoundingClientRect()
1712	      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
1713	    }
1714	    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
1715	    this.scrollbarWidth = this.measureScrollbar()
1716	  }
1717
1718	  Modal.prototype.setScrollbar = function () {
1719	    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
1720	    this.originalBodyPad = document.body.style.paddingRight || ''
1721	    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
1722	  }
1723
1724	  Modal.prototype.resetScrollbar = function () {
1725	    this.$body.css('padding-right', this.originalBodyPad)
1726	  }
1727
1728	  Modal.prototype.measureScrollbar = function () { // thx walsh
1729	    var scrollDiv = document.createElement('div')
1730	    scrollDiv.className = 'modal-scrollbar-measure'
1731	    this.$body.append(scrollDiv)
1732	    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
1733	    this.$body[0].removeChild(scrollDiv)
1734	    return scrollbarWidth
1735	  }
1736
1737
1738	  // MODAL PLUGIN DEFINITION
1739	  // =======================
1740
1741	  function Plugin(option, _relatedTarget) {
1742	    return this.each(function () {
1743	      var $this   = $(this)
1744	      var data    = $this.data('bs.modal')
1745	      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
1746
1747	      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
1748	      if (typeof option == 'string') data[option](_relatedTarget)
1749	      else if (options.show) data.show(_relatedTarget)
1750	    })
1751	  }
1752
1753	  var old = $.fn.modal
1754
1755	  $.fn.modal             = Plugin
1756	  $.fn.modal.Constructor = Modal
1757
1758
1759	  // MODAL NO CONFLICT
1760	  // =================
1761
1762	  $.fn.modal.noConflict = function () {
1763	    $.fn.modal = old
1764	    return this
1765	  }
1766
1767
1768	  // MODAL DATA-API
1769	  // ==============
1770
1771	  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
1772	    var $this   = $(this)
1773	    var href    = $this.attr('href')
1774	    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
1775	    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
1776
1777	    if ($this.is('a')) e.preventDefault()
1778
1779	    $target.one('show.bs.modal', function (showEvent) {
1780	      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
1781	      $target.one('hidden.bs.modal', function () {
1782	        $this.is(':visible') && $this.trigger('focus')
1783	      })
1784	    })
1785	    Plugin.call($target, option, this)
1786	  })
1787
1788	}(jQuery);
1789
1790
1791/***/ }),
1792
1793/***/ 274:
1794/***/ (function(module, exports) {
1795
1796	(function () {
1797
1798	    $.urlParam = function (name) {
1799	        return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [, ""])[1].replace(/\+/g, '%20')) || null;
1800	    };
1801
1802	    $.validateErrorPlacement = function (error, element) {
1803	        var pos = element.position();
1804	        var widthElem = element.outerWidth();
1805
1806
1807	        var errorBoxAddClass, posLeft, errorBoxCss;
1808
1809	        if (element.hasClass('error-pos-left')) {
1810	            errorBoxAddClass = 'error-box-left';
1811	            errorBoxCss = {};
1812	        }
1813	        else {
1814	            errorBoxAddClass = '';
1815	            errorBoxCss = {left: pos.left + widthElem};
1816	        }
1817
1818	        element.after('<div class="error-box ' + errorBoxAddClass + '"></div>');
1819
1820	        element.next('.error-box').css({ top: pos.top }).css(errorBoxCss)
1821	            .append('<div class="error-arrow"></div>').append(error);
1822
1823	    };
1824
1825	    $.validateHighlight = function (element, errorClass, validClass) {
1826	        $(element).addClass(errorClass);
1827	        $(element).next('.error-box').find('.error-arrow').show();
1828	    };
1829
1830	    $.validateUnhighlight = function (element, errorClass, validClass) {
1831	        $(element).removeClass(errorClass).addClass(validClass);
1832	        $(element).next('.error-box').find('.error-arrow').hide();
1833	    };
1834
1835
1836	    $.fn.wkdaValidate = function (options) {
1837
1838	        if (typeof options === "object") {
1839	            options = $.extend(true, options, {
1840	                errorClass: 'error',
1841	                errorElement: 'div',
1842	                errorPlacement: $.validateErrorPlacement,
1843	                highlight: $.validateHighlight,
1844	                unhighlight: $.validateUnhighlight
1845	            });
1846	        }
1847
1848	        return this.validate(options);
1849	    };
1850
1851	    /**
1852	     * add wkdaCookieForm to form AFTER select-chains
1853	     */
1854	    $.fn.wkdaCookieForm = function(options) {
1855
1856	        var cookieOptions = { expires: 730, json: false, path: '/' };
1857
1858	        var $form = $(this);
1859
1860	        var defaults = {
1861	            load: true
1862	        };
1863	        options = $.extend({}, defaults, options);
1864
1865	        var prefix = options.pref;
1866
1867	        var cookieName = function(name) {
1868	            return 'wkdaCF_' + name;
1869	        };
1870
1871	        var setFieldValue = function($field, value) {
1872
1873	            if ($field.is('select')) {
1874	                var valueExists = $field.find("option[value='" + value + "']").length > 0;
1875	                if (valueExists) $field.val(value).change();
1876	            }
1877	            else if ($field.is(':radio')) {
1878	                var $filtered = $field.filter('[value="' + value + '"]');
1879	                $filtered.prop('checked', true);
1880	            }
1881	            else {
1882	                $field.val(value).change();
1883	            }
1884	        };
1885
1886	        var getFieldValue = function($field) {
1887	            if ($field.is(':radio')) {
1888	                return $field.filter(':checked').val();
1889	            }
1890	            else {
1891	                return $field.val();
1892	            }
1893	        };
1894
1895	        var getField = function(fieldName) {
1896	            return $form.find("[name='" + prefix + '[' + fieldName + ']' + "']");
1897	        };
1898
1899	        //-- on submit, read form fields and set cookie
1900	        this.submit(function() {
1901	            var fields = options.fields;
1902
1903	            var values = [];
1904
1905	            $.each(fields, function(idx, formName) {
1906	                var $field = getField(formName);
1907	                var value = getFieldValue($field);
1908
1909	                values.push(encodeURIComponent(formName) + '=' + encodeURIComponent(value));
1910	            });
1911
1912	            var valuesLine = values.join('|');
1913
1914	            $.cookie(cookieName(prefix), valuesLine, cookieOptions);
1915
1916	        });
1917
1918
1919	        //-- cookie set?
1920	        var cookie = $.cookie(cookieName(prefix));
1921	        if (options.load && cookie) {
1922	            var changeCallbacks = $.Callbacks();
1923
1924	            $.each(cookie.split('|'), function(idx, part) {
1925	                var keyValue   = part.split('=');
1926	                var fieldName  = decodeURIComponent(keyValue[0]);
1927	                var fieldValue = decodeURIComponent(keyValue[1]);
1928
1929	                var $field = getField(fieldName);
1930
1931	                var isTarget = $field.data('select-chain-is-target');
1932
1933	                if (isTarget) {
1934	                    // dont use 'once'
1935	                    $field.on('select-chain-complete', function(e) {
1936	                        setFieldValue($field, fieldValue);
1937	                    });
1938	                }
1939	                else {
1940	                    changeCallbacks.add(function() {
1941	                        setFieldValue($field, fieldValue);
1942	                    });
1943	                }
1944	            });
1945	            changeCallbacks.fire();
1946	        }
1947
1948	        return this;
1949	    };
1950
1951	    $.log = function () {
1952	        if ('console' in window) console.log.apply(console, arguments);
1953	    };
1954
1955	}());
1956
1957
1958/***/ }),
1959
1960/***/ 279:
1961/***/ (function(module, exports) {
1962
1963	/**
1964	 * patched version remy's selectChain plugin:
1965	 * http://remysharp.com/2007/09/18/auto-populate-multiple-select-boxes/
1966	 *
1967	 * added 'beforeSend' and 'complete' ajax handler in settings
1968	 */
1969
1970	(function ($) {
1971	    $.fn.selectChain = function (options) {
1972	        var defaults = {
1973	            key: "id",
1974	            value: "label",
1975	            group: null,
1976	            selectFirstOption: true,
1977	            beforeSend: function () {
1978	                return true;
1979	            },
1980	            complete: jQuery.noop
1981	        };
1982
1983	        var settings = $.extend({}, defaults, options);
1984
1985	        if (!(settings.target instanceof $)) settings.target = $(settings.target);
1986
1987	        return this.each(function () {
1988	            var $$ = $(this);
1989
1990	            settings.target.data('select-chain-is-target',$$);
1991
1992	            $$.change(function () {
1993	                var data = null;
1994	                if (typeof settings.data == 'string') {
1995	                    data = settings.data + '&' + this.name + '=' + $$.val();
1996	                } else if (typeof settings.data == 'object') {
1997	                    data = settings.data;
1998	                    data[this.name] = $$.val();
1999	                }
2000
2001	                /** Clears following select elements if value is changed
2002	                  * prevents requests being made, instead checks position in defined selectchain-group and clears elements manually
2003	                **/
2004	                if (typeof settings.group == 'string' && data[this.name].length < 1) {
2005	                  var resetSelect = $(settings.group).index($$);
2006	                  $(settings.group).filter(function (i) {
2007	                    i+2;
2008	                    return i > resetSelect;
2009	                  }).html('')
2010	                    .attr('disabled', true);
2011
2012	                  return;
2013	                }
2014
2015	                $.ajax({
2016	                    url: settings.url,
2017	                    data: data,
2018	                    type: (settings.type || 'get'),
2019	                    dataType: 'json',
2020	                    beforeSend: settings.beforeSend,
2021	                    complete: function() {
2022	                        settings.complete();
2023	                    },
2024	                    success: function (j) {
2025	                        settings.target.empty();
2026
2027	                        var options = [], i = 0, o = null;
2028
2029	                        for (i = 0; i < j.length; i++) {
2030	                            // required to get around IE bug (http://support.microsoft.com/?scid=kb%3Ben-us%3B276228)
2031	                            o = document.createElement("OPTION");
2032	                            o.value = typeof j[i] == 'object' ? j[i][settings.key] : j[i];
2033	                            o.text = typeof j[i] == 'object' ? j[i][settings.value] : j[i];
2034	                            settings.target.get(0).options[i] = o;
2035	                        }
2036
2037	                        //select the first option if we have only one option to select from
2038	                        var selector = j.length == 2 ? 'option:eq(1)' : 'option:first';
2039
2040	                        // hand control back to browser for a moment
2041	                        setTimeout(function () {
2042	                            if(settings.selectFirstOption){
2043	                                settings.target
2044	                                    .find(selector)
2045	                                    .attr('selected', 'selected');
2046	                            }
2047	                            settings.target.trigger('change');
2048	                            settings.target.trigger('select-chain-complete');
2049	                        }, 0);
2050	                    },
2051	                    error: function (xhr, desc, er) {
2052	                        // add whatever debug you want here.
2053	                        //alert("an error occurred");
2054	                    }
2055	                });
2056	            });
2057	        });
2058	    };
2059	})(jQuery);
2060
2061
2062/***/ }),
2063
2064/***/ 281:
2065/***/ (function(module, exports, __webpack_require__) {
2066
2067	/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["feedbackQuestionnaireModule"] = __webpack_require__(282);
2068	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
2069
2070/***/ }),
2071
2072/***/ 282:
2073/***/ (function(module, exports) {
2074
2075	$(function () {
2076	  if ($('div.unsubscribe').length !== 0) {
2077
2078	    //IE 8
2079	    if (document.documentMode !== undefined && document.documentMode === 8) {
2080	      $('.video iframe').hide();
2081	      $('.video img').show();
2082
2083	      $('.form .checkboxes label').each(function () {
2084	        var label = $(this);
2085
2086	        if (label.prev('input').is(':checked')) {
2087	          label.removeClass('checkedi');
2088	          label.prev('input').prop('checked', false);
2089	        } else {
2090	          label.addClass('checkedi');
2091	          label.prev('input').prop('checked', true);
2092	        }
2093	      });
2094
2095	      $('.form .checkboxes label').on('click', function () {
2096	        var label = $(this);
2097
2098	        if (label.prev('input').is(':checked')) {
2099	          label.removeClass('checkedi');
2100	          label.prev('input').prop('checked', false);
2101	        } else {
2102	          label.addClass('checkedi');
2103	          label.prev('input').prop('checked', true);
2104	        }
2105	        label.prev('input').trigger('change');
2106	      });
2107
2108	      $('.receive input:radio').on('change', function () {
2109	        var noEmails = $('#form_receive_4').is(':checked');
2110
2111	        $('#form_sale').next('label').toggleClass('checkedi', noEmails);
2112	        $('#form_market').next('label').toggleClass('checkedi', noEmails);
2113	        $('#form_offer').next('label').toggleClass('checkedi', noEmails);
2114	        $('#form_price').next('label').toggleClass('checkedi', noEmails);
2115	      });
2116	    }
2117
2118	    if ($('#form_receive_4').is(':checked')) {
2119	      $('.detailed').removeClass('hide');
2120	    }
2121
2122	    $('.receive input:radio').on('change', function () {
2123	      $('.error').addClass('hide');
2124	      $('.warning').addClass('hide');
2125	      $('.detailed').toggleClass('hide', !$('#form_receive_4').is(':checked'));
2126	      if (!$('.receive input:checked').is(':checked')) {
2127	        $('.error').toggleClass('hide', $('#form_receive_4').is(':checked'));
2128	      }
2129	      $('#form_sale').prop('checked', $('#form_receive_4').is(':checked'));
2130	      $('#form_market').prop('checked', $('#form_receive_4').is(':checked'));
2131	      $('#form_offer').prop('checked', $('#form_receive_4').is(':checked'));
2132	      $('#form_price').prop('checked', $('#form_receive_4').is(':checked'));
2133	    });
2134
2135	    $('#form_survey_3').on('click', function () {
2136	      $('.detailed').toggleClass('hide', !$(this).is(':checked'));
2137	    });
2138
2139	    $('#form_survey input:radio').on('change', function () {
2140	      if ($(this).val() === '4') {
2141	        $('#form_other').removeClass('hide');
2142	        $('#form_other').focus();
2143	      } else {
2144	        $('#form_other').addClass('hide');
2145	      }
2146	    });
2147
2148	    $('#form_sale, #form_market, #form_offer, #form_price').on('change', function () {
2149	      if (!$('#form_sale').is(':checked')
2150	        && !$('#form_market').is(':checked')
2151	        && !$('#form_offer').is(':checked')
2152	        && !$('#form_price').is(':checked')
2153	        && $('.warning').hasClass('hide')
2154	        && !$('.detailed').hasClass('hide')) {
2155
2156	        $('.warning').removeClass('hide');
2157	      } else {
2158	        $('.warning').addClass('hide');
2159	      }
2160	    });
2161
2162	    $('.form').submit(function (e) {
2163	      var err = false;
2164
2165	      if (!$('.receive input:checked').is(':checked')
2166	        && !$('#form_receive_4').is(':checked')) {
2167	        err = true;
2168	        $('.error').removeClass('hide');
2169	      }
2170
2171	      if (err) {
2172	        e.preventDefault();
2173	      }
2174	    });
2175
2176	    var init = false;
2177
2178	    $(window).resize(function () {
2179	      waitForFinalEvent(function () {
2180	        $('.video').height($('.happy-customers').height());
2181	        $('#player').height($('.happy-customers').height());
2182	      }, 300, "media-height", init);
2183	      init = true;
2184	    });
2185
2186	    $(window).resize();
2187	  }
2188	});
2189
2190	var waitForFinalEvent = (function () {
2191	  var timers = {};
2192
2193	  return function (callback, ms, uniqueId, init) {
2194	    if (!uniqueId) {
2195	      uniqueId = "media-height";
2196	    }
2197	    if (timers[uniqueId]) {
2198	      clearInterval(timers[uniqueId]);
2199	      clearTimeout(timers[uniqueId]);
2200	    }
2201	    if (init === false) {
2202	      timers[uniqueId] = setInterval(callback, ms);
2203	    } else {
2204	      timers[uniqueId] = setTimeout(callback, ms);
2205	    }
2206	  };
2207	})();
2208
2209	/*
2210	 ==============
2211	 feedback Questionnaire Module
2212	 ==============
2213	 */
2214
2215	var feedbackQuestionnaireModule = module.exports = function() {
2216
2217	    function init() {
2218	        if ($.cookie('wkdaLead') === undefined || $.cookie('wkdaLead') == '') {
2219	            var url = window.location.href.split('/');
2220	            $.cookie('wkdaLead', url[url.length - 2]);
2221	        }
2222
2223	        var cookieData = $.cookie('questionnaireSurvey');
2224	        if (cookieData != undefined && cookieData.lead == $.cookie('wkdaLead') && cookieData.questions.length > 0) {
2225	            setQuestionnaireStatus('complete');
2226	            return;
2227	        }
2228
2229	        getQuestionnaire(function (data) {
2230	            if (data.questions != undefined && data.questions.length > 0) {
2231	                setQuestionnaireStatus('complete');
2232	            } else {
2233	                setQuestionnaireStatus('active');
2234	            }
2235	        });
2236	    }
2237
2238	    var submitQuestionnaire = function (questionnaire) {
2239	        var form = new FormData();
2240	        form.append("type", "customerUnsubscribe");
2241	        var data = [{
2242	            "question": 'unsubscribe-survey',
2243	            "question_text": questionnaire.find('.question').attr('question-data'),
2244	            "answer": questionnaire.find('.answers input[name="answer"]:checked').val(),
2245	            "answer_text": questionnaire.find('.answers input[name="answer"]:checked').attr('answer-data')
2246	        }];
2247
2248	        form.append("questions", JSON.stringify(data));
2249
2250	        var settings = {
2251	            "async": true,
2252	            "crossDomain": true,
2253	            "url": "/car/questionnaire/save/" + $.cookie('wkdaLead') + "/",
2254	            "method": "POST",
2255	            "headers": {
2256	                "cache-control": "no-cache"
2257	            },
2258	            "processData": false,
2259	            "contentType": false,
2260	            "mimeType": "multipart/form-data",
2261	            "data": form
2262	        };
2263
2264	        $.cookie('questionnaireSurvey', JSON.stringify({
2265	            lead: $.cookie('wkdaLead'),
2266	            questions: data
2267	        }));
2268	        $.ajax(settings).complete(function (response) {
2269	            setQuestionnaireStatus('complete');
2270	        });
2271	    };
2272
2273	    var getQuestionnaire = function (callback) {
2274	        var form = new FormData();
2275	        form.append("type", "customerUnsubscribe");
2276	        var settings = {
2277	            "async": true,
2278	            "crossDomain": true,
2279	            "url": "/car/questionnaire/get/" + $.cookie('wkdaLead') + "/",
2280	            "method": "POST",
2281	            "headers": {
2282	                "cache-control": "no-cache"
2283	            },
2284	            "processData": false,
2285	            "contentType": false,
2286	            "mimeType": "multipart/form-data",
2287	            "data": form
2288	        };
2289
2290	        $.ajax(settings).complete(function (response) {
2291	            var responseData = JSON.parse(response.responseText);
2292	            callback(responseData);
2293	        });
2294	    };
2295
2296	    var setQuestionnaireStatus = function (status) {
2297	        var questionnaire = $('.unsubscribe-q-survey');
2298
2299	        questionnaire.data('status', status);
2300	        if (status == 'complete') {
2301	            hasSeenCustomerSurvey = true;
2302	            questionnaire.find('.not-answered').hide();
2303	            questionnaire.find('.answered').show();
2304	            questionnaire.show();
2305	        } else if (status == 'active') {
2306	            questionnaire.show();
2307	        } else if (status == 'inactive') {
2308	            questionnaire.hide();
2309	        }
2310	    };
2311
2312	    $('.unsubscribe-q-survey .not-answered button').on('click', function () {
2313	        submitQuestionnaire($(this).parents('.unsubscribe-q-survey'));
2314	    });
2315
2316	    $('.unsubscribe-q-survey .not-answered input[type=radio]').on('click', function () {
2317	        $(this).parents('.unsubscribe-q-survey').find('button').prop('disabled', false);
2318	    });
2319
2320	    return { init: init};
2321	}();
2322
2323
2324/***/ }),
2325
2326/***/ 284:
2327/***/ (function(module, exports, __webpack_require__) {
2328
2329	/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["privateSaleModule"] = __webpack_require__(285);
2330	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
2331
2332/***/ }),
2333
2334/***/ 285:
2335/***/ (function(module, exports, __webpack_require__) {
2336
2337	var privateSaleModule = module.exports = function () {
2338	  var price, minPrice, zipcode, testdriveHours, testdriveHoursContainer, commentsField, commentsCount, phoneNumber, 
2338countryCode;
2339
2340	  var isInteger = function(val){
2341	    return String(parseInt(val)) === String(val);
2342	  }
2343
2344	  var showError = function(container, errorName){
2345	    $(container).parent().find('.error-wrapper').show();
2346	    $(container).parent().find('.error.' + errorName + '-error').show();
2347	  };
2348
2349	  var validatePrice = function() {
2350	    var currentPrice = $(price).val();
2351	    if(currentPrice.trim() === ''){
2352	      showError(price, 'required');
2353	      return false;
2354	    }
2355	    if(isNaN(currentPrice)){
2356	      showError(price, 'not-a-number');
2357	      return false;
2358	    }
2359	    if(!isInteger(currentPrice)){
2360	      showError(price, 'not-an-integer');
2361	      return false;
2362	    }
2363	    return true;
2364	  };
2365
2366	  var validateMinPrice = function() {
2367	    var currentMinPrice = $(minPrice).val();
2368	    if(currentMinPrice.trim() === ''){
2369	      return true;
2370	    }
2371	    if(isNaN(currentMinPrice)){
2372	      showError(minPrice, 'not-a-number');
2373	      return false;
2374	    }
2375	    if(!isInteger(currentMinPrice)){
2376	      showError(minPrice, 'not-an-integer');
2377	      return false;
2378	    }
2379
2380	    return true;
2381	  };
2382
2383	  var validateZipcode = function(){
2384	    var currentZipcode = $(zipcode).val();
2385	    if(currentZipcode.trim() === ''){
2386	      showError(zipcode, 'required');
2387	      return false;
2388	    }
2389	    if(isNaN(currentZipcode)){
2390	      showError(zipcode, 'not-a-number');
2391	      return false;
2392	    }
2393	    //TODO: get locale to check with each country zipcode
2394	    //currently implementation is will validate only with Germany's zipcode regex
2395	    var digitsRegs = /^\d+$/;
2396	    var hasDigitsOnly = digitsRegs.test(currentZipcode);
2397	    var germanyZipcodeRegex = /\b((?:0[1-46-9]\d{3})|(?:[1-357-9]\d{4})|(?:[4][0-24-9]\d{3})|(?:[6][013-9]\d{3}))\b/;
2398	    var isValidZipcode = germanyZipcodeRegex.test(currentZipcode);
2399	    if(!isValidZipcode || !hasDigitsOnly){
2400	      showError(zipcode, 'not-valid-zipcode');
2401	      return false;
2402	    }
2403	    return true;
2404	  };
2405
2406	  var validatePhoneNumber = function(){
2407	    var number = $(phoneNumber).val();
2408	    var code = $(countryCode).val();
2409
2410	    if(number.trim().length === 0 ){
2411	      showError(phoneNumber, 'required');
2412	      return false;
2413	    }
2414	    if(!isInteger(number)){
2415	      showError(phoneNumber, 'not-a-number');
2416	      return false;
2417	    }
2418	    return true;
2419	  }
2420
2421	  var validateTestdriveHours = function() {
2422	    var checkedOptions = $(testdriveHours).filter(':checked');
2423
2424	    if (checkedOptions.length === 0) {
2425	      showError(testdriveHoursContainer, 'required');
2426	      return false;
2427	    }
2428
2429	    return true;
2430	  };
2431
2432	  var submitForm = function(event){
2433	    var isValidPrice = validatePrice();
2434	    var isValidMinPrice = validateMinPrice();
2435	    var isValidZipcode = validateZipcode();
2436	    var isValidTestdriveHours = validateTestdriveHours();
2437	    // When returning false the submit doesn't happen
2438	    return isValidPrice && isValidMinPrice && isValidZipcode && isValidTestdriveHours;
2439	  };
2440
2441	  function preventExceedingLimit(limit, event) {
2442	    var field = event.target;
2443
2444	    var selectionStart = field.selectionStart;
2445	    var selectionEnd = field.selectionEnd;
2446
2447	    // If no text selected
2448	    if (selectionStart === selectionEnd) {
2449	      // Prevent printable key if limit has already been reached
2450	      // Also prevent Enter key
2451	      if (field.value.length >= limit || event.key === 'Enter') {
2452	        // Check for backspace and arrow keys because
2453	        // some browsers trigger keypress for them
2454	        if (event.keyCode !== 8 && (event.keyCode < 37 || event.keyCode > 40)) {
2455	          event.preventDefault();
2456	        }
2457	      }
2458	    }
2459	  }
2460
2461	  function setOtherReasonFieldCharactersLimit($otherReasonField) {
2462	    var limit = 50;
2463
2464	    $otherReasonField.on('keypress', preventExceedingLimit.bind(null, limit));
2465
2466	    $otherReasonField.on('keyup change', function(event) {
2467	      var field = event.target;
2468
2469	      // Save cursor position in text
2470	      var selectionStart = field.selectionStart;
2471	      var selectionEnd = field.selectionEnd;
2472
2473	      // If limit has been exceeded (i.e. by pasting)
2474	      // trim the field content to the established limit
2475	      if (field.value.length > limit) {
2476	        field.value = field.value.slice(0, limit);
2477	      }
2478
2479	      // Restore cursor position in text
2480	      field.selectionStart = selectionStart;
2481	      field.selectionEnd = selectionEnd;
2482	    });
2483	  }
2484
2485	  var setCommentsFieldCharactersLimitAndCount = function($commentsField) {
2486	    var limit = 500;
2487
2488	    $commentsField.on('keypress', preventExceedingLimit.bind(null, limit));
2489	    $commentsField.on('keyup', fixFieldContentAndUpdateCounter);
2490	    $commentsField.on('change', fixFieldContentAndUpdateCounter);
2491
2492	    fixFieldContentAndUpdateCounter({ target: $commentsField[0] });
2493
2494	    function fixFieldContentAndUpdateCounter(event) {
2495	      var field = event.target;
2496
2497	      // Save cursor position in text
2498	      var selectionStart = field.selectionStart;
2499	      var selectionEnd = field.selectionEnd;
2500
2501	      // Remove any emoji from the field value
2502	      clearEmojis(field);
2503
2504	      // If limit has been exceeded (i.e. by pasting)
2505	      // trim the field content to the established limit
2506	      if (field.value.length > limit) {
2507	        field.value = field.value.slice(0, limit);
2508	      }
2509
2510	      // Restore cursor position in text
2511	      field.selectionStart = selectionStart;
2512	      field.selectionEnd = selectionEnd;
2513
2514	      // Update counter
2515	      commentsCount.html(event.target.value.length);
2516	    }
2517
2518	    function clearEmojis(field) {
2519	      var emojis = /([\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2694-\u2697]|\uD83E[\uDD10-\uDD5D])/g;
2520
2521	      field.value = field.value.replace(
2522	        new RegExp(emojis),
2523	        ''
2524	      );
2525	    }
2526	  }
2527
2528	  var setForm = function(selector){
2529	    price = $(selector + ' input[name="car_private_sale_type[expectedPrice]"]');
2530	    minPrice = $(selector + ' input[name="car_private_sale_type[painPrice]"]');
2531	    zipcode = $(selector + ' input[name="car_private_sale_type[zipCode]"]');
2532	    testdriveHours = $(selector + ' input[name="car_private_sale_type[testdriveHours][]"]');
2533	    testdriveHoursContainer = $(selector + ' .js-test-drive-hours');
2534	    commentsField = $(selector + ' [name="car_private_sale_type[comments]"]');
2535	    commentsCount = $(selector + ' .js-comments-count');
2536	    var submitButton =$(selector + ' .submit-button-row button');
2537	    var hideErrors = function(e){
2538	      var code = e.which;
2539	      //dont remove errors on enter or tab
2540	      if (code !== 13 && code !== 9) {
2541	        $(selector + ' .error-wrapper').hide();
2542	        $(selector + ' .error-wrapper .error').hide();
2543	      }
2544	    };
2545	    $(price).keyup(hideErrors);
2546	    $(minPrice).keyup(hideErrors);
2547	    $(zipcode).keyup(hideErrors);
2548	    $(testdriveHours).change(hideErrors);
2549	    $(selector).submit(submitForm);
2550	    setCommentsFieldCharactersLimitAndCount(commentsField);
2551	  };
2552
2553	  var setPhoneUpdateForm = function(parentSelector, url) {
2554	    var jParent = $(parentSelector);
2555	    var jTriggerButton = jParent.find('.bcn-phone-trigger');
2556	    var jSaveButton = jParent.find('#phone-save-btn');
2557	    var jErrorBox = $(parentSelector).find('.error-box');
2558	    var jOtherError = $(parentSelector).find('.error-box .error');
2559	    var jEmptyError = $(parentSelector).find('.error-box .error-empty');
2560
2561	    jTriggerButton.click(function(event) {
2562	      event.preventDefault();
2563	      jParent.addClass('show');
2564	    });
2565
2566	    jSaveButton.click(function(event) {
2567	      event.preventDefault();
2568
2569	      var prefix = jParent.find('select[name="prefix"]').val();
2570	      var phone = jParent.find('input[name="phone"]').val();
2571
2572	      jErrorBox.hide();
2573	      jEmptyError.hide();
2574	      jOtherError.hide();
2575
2576	      if (phone.length > 0) {
2577	        $.ajax({
2578	          type: 'POST',
2579	          url: url,
2580	          data: JSON.stringify({
2581	            phone: prefix + '' + phone,
2582	          }),
2583	          contentType: "application/json",
2584	          success: function() {
2585	            jParent.find('.phone span').text(prefix + ' ' + phone);
2586	            jErrorBox.hide();
2587	            jParent.removeClass('show');
2588	          },
2589	          error: function() {
2590	            jErrorBox.show();
2591	            jEmptyError.hide();
2592	            jOtherError.show();
2593	          }
2594	        });
2595	      } else {
2596	        jErrorBox.show();
2597	        jEmptyError.show();
2598	        jOtherError.hide();
2599	      }
2600	    });
2601	  }
2602
2603	  var initDashboard = function(selectors) {
2604	    var privateSaleDashboard = __webpack_require__(286);
2605
2606	    commentsField = $(selectors.comments);
2607	    commentsCount = $(selectors.commentsCounter);
2608	    otherReasonField = $('[name=otherReasonDetails]');
2609
2610	    privateSaleDashboard.initPopUpForms();
2611	    privateSaleDashboard.initListingPriceForm();
2612	    privateSaleDashboard.initCommentsForm();
2613	    privateSaleDashboard.initTestdriveForm();
2614	    privateSaleDashboard.initOthersForm();
2615
2616	    privateSaleDashboard.initHeaderMenu();
2617	    privateSaleDashboard.initSidebar();
2618
2619	    setCommentsFieldCharactersLimitAndCount(commentsField);
2620	    setOtherReasonFieldCharactersLimit(otherReasonField);
2621	  };
2622
2623	  var initViewsChart = function(values, chart){
2624	    var tabletMinWidth = 768;
2625	    var aggregate = function(data){
2626	      if(data.length < 15){
2627	        return data;
2628	      }
2629
2630	      var bucketsSize = Math.ceil(data.length / 7);
2631	      var buckets = Array(bucketsSize);
2632	      for(var index = 0 ; index < data.length ; index++){
2633	        var currentDay = index;
2634	        var bucketIndex = Math.floor(currentDay / 7);
2635	        if(buckets[bucketIndex]){
2636	          buckets[bucketIndex].views += data[index].views;
2637	        }else{
2638	          buckets[bucketIndex] = {
2639	            views: data[index].views,
2640	            day: data[index].day,
2641	          };
2642	        }
2643	      }
2644
2645	      return buckets;
2646	    };
2647	    var getPaddingLeft = function(maxValue){
2648	      var span = $('<span style="font-size: 12px;">'+maxValue+'</span>');
2649	      $(chart).append(span);
2650	      return span.width() + 10;
2651	    };
2652	    var getMaxValue = function(data){
2653	      var maxValue = 0;
2654	      for (var index = 0 ; index < data.length ; index ++ ){
2655	          var views = ~~data[index].views;
2656	          if(data[index].views > maxValue ){
2657	            maxValue = views;
2658	          }
2659	      }
2660	      (maxValue % 2) && maxValue++;
2661	      if(maxValue === 0 ){
2662	        maxValue = 10;
2663	      }
2664
2665	      return maxValue;
2666	    };
2667	    var getMobileTickValues = function(data){
2668	      var ticks = [];
2669	      var maxTicks = 3;
2670	      if(data.length <= maxTicks){
2671	        for(var index = 0 ; index < data.length ; index++){
2672	          ticks.push(data[index].day);
2673	        }
2674	      }else{
2675	        var firstDay = data[0].day;
2676	        var lastDay = data[data.length-1].day;
2677
2678	        var format = d3.time.format("%d.%m.%y");
2679	        var diff = +format.parse(lastDay) - +format.parse(firstDay);
2680	        var midRange = +format.parse(firstDay) + diff/2;
2681
2682	        ticks.push(firstDay);
2683	        ticks.push(format(new Date(midRange)));
2684	        ticks.push(lastDay);
2685	      }
2686
2687	      return ticks;
2688	    };
2689	    // The following function is used to draw/redraw the chart
2690	    var drawChart = function(isDesktop){
2691	      if(chart.destroy){
2692	        // Destroy the chart before redrawing
2693	        chart = chart.destroy();
2694	      }
2695	      opts.axis = isDesktop ? desktopAxisOpts : mobileAxisOpts;
2696	      chart = c3.generate(opts);
2697	    };
2698	    var $window = $(window);
2699	    var aggregatedValues = aggregate(values);
2700	    var maxValue = getMaxValue(aggregatedValues);
2701	    var isDesktop = $window.width() >= tabletMinWidth;
2702	    var paddingLeft = getPaddingLeft(maxValue);
2703
2704	    var opts = {
2705	        padding: {
2706	            left: paddingLeft,
2707	            right: 10,
2708	        },
2709	        size: {
2710	            height: 95,
2711	        },
2712	        bindto: chart,
2713	        data: {
2714	            x: 'date',
2715	            xFormat: '%d.%m.%y',
2716	            json : aggregatedValues,
2717	            keys:{
2718	                x: 'day',
2719	                value: ['views']
2720	            }
2721	        },
2722	        legend: {
2723	            show: false,
2724	        },
2725	        tooltip: {
2726	            grouped: false,
2727	            contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
2728	                var value = d[0].value;
2729
2730	                return '<div class="views-chart-tooltip">'+value+'</div>';
2731	            },
2732	            position: function (data, tooltipWidth, height, thisElement) {
2733	                var containerWidth, x, y;
2734	                var element = document.getElementById("views-chart");
2735	                var paddingY = -10;
2736	                containerWidth = element.clientWidth;
2737	                x = parseInt(thisElement.getAttribute('cx')) + paddingLeft - (tooltipWidth / 2 );
2738	                if (x + tooltipWidth > containerWidth) {
2739	                    x = containerWidth - tooltipWidth - 2;
2740	                }
2741	                y = thisElement.getAttribute('cy');
2742	                y = y - height + paddingY;
2743	                return {
2744	                    top: y,
2745	                    left: x
2746	                };
2747	            }
2748	        },
2749	        grid: {
2750	            y: {
2751	                show: true
2752	            }
2753	        }
2754	    };
2755	    var yAxisOpts = {
2756	        max: maxValue,
2757	        min: 0,
2758	        tick: {
2759	            values: [0, Math.floor(maxValue / 2), maxValue],
2760	        }
2761	    };
2762	    var xAxisPadding = 1000 * 60 * 60 * 24; //half a day padding
2763	    if(values.length > 30){
2764	      xAxisPadding *= 3; //one and half a day padding
2765	    }
2766	    var mobileAxisOpts = {
2767	        x: {
2768	            type: 'timeseries',
2769	            tick: {
2770	                format: '%d.%m',
2771	                values: getMobileTickValues(aggregatedValues),
2772	            },
2773	            padding: {
2774	              left: xAxisPadding,
2775	              right: xAxisPadding
2776	            }
2777	        },
2778	        y: yAxisOpts
2779	    };
2780	    var desktopAxisOpts = {
2781	        x: {
2782	            type: 'timeseries',
2783	            tick: {
2784	                format: '%d.%m',
2785	                culling: false,
2786	            }
2787	        },
2788	        y: yAxisOpts
2789	    };
2790
2791	    drawChart(isDesktop);
2792
2793	    $(document).ready(function() {
2794	      $window.resize(function() {
2795	          var currentWidth = $window.width();
2796	          if (currentWidth < tabletMinWidth && isDesktop) {
2797	            isDesktop = false;
2798	            drawChart(isDesktop);
2799	          }else if(currentWidth >= tabletMinWidth && !isDesktop){
2800	            isDesktop = true;
2801	            drawChart(isDesktop);
2802	          }
2803	      });
2804	    });
2805	  }
2806
2807	  return {
2808	    setForm: setForm,
2809	    setPhoneUpdateForm: setPhoneUpdateForm,
2810	    initDashboard: initDashboard,
2811	    initViewsChart: initViewsChart,
2812	  };
2813	}();
2814
2815
2816/***/ }),
2817
2818/***/ 286:
2819/***/ (function(module, exports, __webpack_require__) {
2820
2821	var DOM = __webpack_require__(287);
2822	var privateSaleApi = __webpack_require__(288);
2823
2824	// Find and store UI elements
2825	var UI = {
2826	  popupForms: {
2827	    allPopups: $('.js-popup-form'),
2828	    showButtons: $('.js-popup-form-show'),
2829	    hideButtons: $('.js-popup-form-hide'),
2830	    formKeys: ['callMeBack', 'soldMyCar']
2831	  },
2832	  listingPrice: {
2833	    loadingMessage: $('#listing-price-loading-message'),
2834	    successMessage: $('#listing-price-success-message'),
2835	    errorMessage: $('#listing-price-error-message'),
2836	    confirmationDialog: $('#listing-price-confirmation-dialog'),
2837	    form: $('#listing-price-form'),
2838	    button: $('#listing-price-button')
2839	  },
2840	  callMeBack: {
2841	    loadingMessage: $('.js-call-me-back-loading-message'),
2842	    successMessage: $('.js-call-me-back-success-message'),
2843	    errorMessage: $('.js-call-me-back-error-message'),
2844	    form: $('#call-me-back-form'),
2845	    popupId: 'call-me-back-popup-form',
2846	    button: $('#call-me-back-form-button')
2847	  },
2848	  soldMyCar: {
2849	    loadingMessage: $('#sold-my-car-loading-message'),
2850	    successMessage: $('#sold-my-car-success-message'),
2851	    errorMessage: $('#sold-my-car-error-message'),
2852	    form: $('#sold-my-car-form'),
2853	    popupId: 'sold-my-car-popup-form',
2854	    button: $('#sold-my-car-form-button')
2855	  },
2856	  comments: {
2857	    form: $('#comments-form'),
2858	    button: $('#comments-form-button'),
2859	    loadingMessage: $('#comments-loading-message'),
2860	    successMessage: $('#comments-success-message'),
2861	    errorMessage: $('#comments-error-message')
2862	  },
2863	  testdrive: {
2864	    loadingMessage: $('#testdrive-loading-message'),
2865	    successMessage: $('#testdrive-success-message'),
2866	    errorMessage: $('#testdrive-error-message'),
2867	    form: $('#testdrive-form')
2868	  },
2869	  others: {
2870	    form: $('#others-form'),
2871	    loadingMessage: $('#others-form-loading-message'),
2872	    errorMessage: $('#others-form-error-message'),
2873	    successMessage: $('#others-form-success-message')
2874	  }
2875	};
2876
2877	// Data shared throughout the UI
2878	var sharedData = {
2879	  maxListingPrice: Number(UI.listingPrice.form[0].price.value),
2880	  minimumPrice: Number(UI.others.form[0].minimumPrice.value),
2881	  phoneCode: UI.callMeBack.form[0].phoneCode.value,
2882	  phoneNumber: Number(UI.callMeBack.form[0].phoneNumber.value)
2883	};
2884
2885	/**
2886	 * Updates UI elements after one of the private sale dashboard forms is submitted
2887	 * Expects a valid key and a jqXHR like object (http://api.jquery.com/jQuery.ajax/#jqXHR)
2888	 * @param {Object} request
2889	 * @param {Function} request.done
2890	 * @param {Function} request.fail
2891	 * @param {Function} request.always
2892	 * @param {string} key A string representing the form. May be one of the following values: 'listingPrice', 'callMeBack', 'soldMyCar', 'comments', 'testdrive', 'others'
2893	 */
2894	function updateUI(request, key) {
2895	  var validKeys = Object.keys(UI);
2896
2897	  if (
2898	    typeof request !== 'object' ||
2899	    typeof request.done !== 'function' ||
2900	    typeof request.fail !== 'function' ||
2901	    typeof request.always !== 'function'
2902	  ) {
2903	    throw new TypeError('Argument request must provide done, fail and always methods');
2904	  }
2905
2906	  if (validKeys.indexOf(key) < 0) {
2907	    throw new TypeError('Argument key must be one of: ' + validKeys.join(', '));
2908	  }
2909
2910	  // Get UI elements
2911	  var loadingMessage = UI[key].loadingMessage;
2912	  var successMessage = UI[key].successMessage;
2913	  var errorMessage = UI[key].errorMessage;
2914	  var button = UI[key].button;
2915	  var form = UI[key].form;
2916
2917	  // Show loading message
2918	  DOM.showElement(loadingMessage);
2919
2920	  // Disable form fields
2921	  DOM.disableForm(form);
2922
2923	  // Hide success and error message
2924	  DOM.hideElement(successMessage);
2925	  DOM.hideElement(errorMessage);
2926
2927	  request.done(function() { DOM.showElement(successMessage); });
2928	  request.fail(function() { DOM.showElement(errorMessage); });
2929
2930	  // Always hide loading message when request finishes
2931	  // and enable form fields
2932	  request.always(function() {
2933	    DOM.hideElement(loadingMessage);
2934	    DOM.enableForm(form);
2935	  });
2936	}
2937
2938	/**
2939	 * Similar to updateUI but performs more actions which are specific for popup forms
2940	 * Expects a valid key and a jqXHR like object (http://api.jquery.com/jQuery.ajax/#jqXHR)
2941	 * @param {Object} request
2942	 * @param {Function} request.done
2943	 * @param {Function} request.fail
2944	 * @param {Function} request.always
2945	 * @param {string} key A string representing the form. May be one of the following values: 'callMeBack', 'soldMyCar'
2946	 */
2947	function updateUIForPopupForm(request, key) {
2948	  var allPopups = UI.popupForms.allPopups;
2949	  var showButtons = UI.popupForms.showButtons;
2950
2951	  // store this popup
2952	  var popup = allPopups.filter('#' + UI[key].popupId);
2953
2954	  // store show buttons for all popups but this one
2955	  var otherPopupShowButtons = showButtons.filter(function() {
2956	    return $(this).attr('data-target') !== UI[key].popupId;
2957	  });
2958
2959	  // Hide popup
2960	  DOM.hideElement(popup);
2961	  // Disable show buttons
2962	  DOM.disableElement(showButtons);
2963	  // update messages related to request status
2964	  updateUI(request, key);
2965
2966	  // If everything went well
2967	  request.always(function() {
2968	    // enable all the show buttons without exception
2969	    DOM.enableElement(showButtons);
2970	  });
2971	}
2972
2973	/**
2974	 * Hides any Status messages such as loading, success and error messages
2975	 * from previous AJAX requests
2976	 * @param {string} key A string representing the form. May be one of the following values: 'listingPrice', 'callMeBack', 'soldMyCar', 'comments', 'testdrive', 'others'
2977	 */
2978	function hideStatusMessages(key) {
2979	  [
2980	    UI[key].errorMessage,
2981	    UI[key].successMessage,
2982	    UI[key].loadingMessage
2983	  ].forEach(DOM.hideElement);
2984	}
2985
2986	function hidePopupFormStatusMessages() {
2987	  UI.popupForms.formKeys.forEach(function(key) {
2988	    hideStatusMessages(key);
2989	  });
2990	}
2991
2992	/**
2993	 * Reusable callback for jQuery.validate
2994	 * onShowErrors option
2995	 */
2996	function onShowErrors(key) {
2997	  return function(errorMap, errorList) {
2998	    if (errorList.length > 0) {
2999	      hideStatusMessages(key);
3000	    }
3001
3002	    this.defaultShowErrors();
3003	  };
3004	}
3005
3006	/**
3007	 * Initialize the functionality of the
3008	 * Listing Price form
3009	 */
3010	function initListingPriceForm() {
3011	  var dialog = UI.listingPrice.confirmationDialog;
3012	  var form = UI.listingPrice.form;
3013
3014	  var priceField = $(UI.listingPrice.form[0].price);
3015	  var minimumPriceField = $(UI.others.form[0].minimumPrice);
3016
3017	  // Confirmation Dialog Cancel action
3018	  dialog.find('[data-action="cancel"]').on('click', function() {
3019	    DOM.hideElement(dialog);
3020	  });
3021
3022	  // Confirmation Dialog Confirm action
3023	  dialog.find('[data-action="confirm"]').on('click', function() {
3024	    var value = Number(priceField.val());
3025	    var request = privateSaleApi.updateListingPrice(value);
3026
3027	    // Take care of status messages
3028	    updateUI(request, 'listingPrice');
3029
3030	    // Hide dialog
3031	    DOM.hideElement(dialog);
3032
3033	    // If request succeeds
3034	    request.done(function() {
3035	      var listingPrice = value;
3036	      var minimumPrice = sharedData.minimumPrice;
3037	      // Set the price as new max price
3038	      sharedData.maxListingPrice = listingPrice;
3039	      // and set minimal price if necessary
3040	      if (listingPrice < minimumPrice) {
3041	        sharedData.minimumPrice = listingPrice;
3042	        minimumPriceField.val(listingPrice);
3043	      }
3044	    });
3045	  });
3046
3047	  // Validate and handle submit of form
3048	  form.validate({
3049	    rules: {
3050	      price: {
3051	        required: true,
3052	        number: true,
3053	        digits: true,
3054	        max: function() {
3055	          return sharedData.maxListingPrice;
3056	        }
3057	      }
3058	    },
3059	    submitHandler: function() {
3060	      var value = priceField.val();
3061	      dialog.find('[data-value-name="price"]').html(value);
3062	      DOM.showElement(dialog);
3063	    },
3064	    errorPlacement: function(error, element) {
3065	      if (element.attr('name') === 'price') {
3066	        return error.insertAfter('#listing-price');
3067	      }
3068
3069	      error.insertAfter(element);
3070	    },
3071	    showErrors: onShowErrors('listingPrice')
3072	  });
3073	}
3074
3075	/**
3076	 * Initialize the functionality of the
3077	 * Call Me Back and Sold My Car popup forms
3078	 */
3079	function initPopUpForms() {
3080	  var allPopups = UI.popupForms.allPopups;
3081	  var showButtons = UI.popupForms.showButtons;
3082	  var hideButtons = UI.popupForms.hideButtons;
3083
3084	  var callMeBackForm = UI.callMeBack.form;
3085	  var soldMyCarForm = UI.soldMyCar.form;
3086
3087	  var callMeBackReasons = callMeBackForm.find('[name="reason"]');
3088	  var soldMyCarReasons = soldMyCarForm.find('[name="reason"]');
3089
3090	  // Enable submit button after choosing a reason
3091	  callMeBackReasons.on('change', function() {
3092	    DOM.enableElement(UI.callMeBack.button);
3093	    // Then remove the event listener since the reason
3094	    // can be modified but not removed
3095	    callMeBackReasons.off('change');
3096	  });
3097
3098	  // Enable submit button after choosing a reason
3099	  soldMyCarReasons.on('change', function() {
3100	    DOM.enableElement(UI.soldMyCar.button);
3101	    // Then remove the event listener since the reason
3102	    // can be modified but not removed
3103	    soldMyCarReasons.off('change');
3104	  });
3105
3106	  showButtons.on('click', function(event) {
3107	    var popupId = $(event.target).attr('data-target');
3108	    var popup = allPopups.filter('#' + popupId);
3109
3110	    // Hide any previous existing popup form status message
3111	    hidePopupFormStatusMessages();
3112
3113	    DOM.hideElement(allPopups);
3114	    DOM.showElement(popup);
3115	  });
3116
3117	  hideButtons.on('click', function(event) {
3118	    var popupId = $(event.target).attr('data-target');
3119	    var popup = allPopups.filter('#' + popupId);
3120
3121	    DOM.hideElement(popup);
3122	  });
3123
3124	  // Validate call me back form
3125	  callMeBackForm.validate({
3126	    rules: {
3127	      reason: 'required',
3128	      otherReasonDetails: {
3129	        required: {
3130	          depends: function() {
3131	            return $('#call-me-back-reason-other').is(':checked');
3132	          }
3133	        }
3134	      },
3135	      phoneNumber: { required: true, digits: true }
3136	    },
3137	    submitHandler: function() {
3138	      var phoneNumber = Number(DOM.getFieldValue(callMeBackForm, 'phoneNumber'));
3139	      var phoneCode = DOM.getFieldValue(callMeBackForm, 'phoneCode');
3140	      var reason = DOM.getFieldValue(callMeBackForm, 'reason');
3141	      var otherReasonDetails = DOM.getFieldValue(callMeBackForm, 'otherReasonDetails');
3142
3143	      var request = privateSaleApi.requestACall(reason, phoneCode, phoneNumber, otherReasonDetails);
3144
3145	      updateUIForPopupForm(request, 'callMeBack');
3146
3147	      request.done(function() {
3148	        var othersForm = UI.others.form;
3149
3150	        sharedData.phoneNumber = phoneNumber;
3151	        sharedData.phoneCode = phoneCode;
3152
3153	        DOM.setFieldValue(othersForm, 'phoneNumber', phoneNumber);
3154	        DOM.setFieldValue(othersForm, 'phoneCode', phoneCode);
3155	      });
3156	    },
3157	    errorPlacement: function(error, element) {
3158	      var name = element.attr('name');
3159
3160	      if (name === 'reason' || name === 'otherReasonDetails') {
3161	        return error.insertAfter('#call-me-back-reason');
3162	      }
3163
3164	      if (name === 'phoneNumber') {
3165	        return error.insertAfter('#call-me-back-phone');
3166	      }
3167
3168	      error.insertAfter(element);
3169	    }
3170	  });
3171
3172	  // Validate sold my car form
3173	  soldMyCarForm.validate({
3174	    rules: { reason: 'required' },
3175	    submitHandler: function() {
3176	      var reason = DOM.getFieldValue(soldMyCarForm, 'reason');
3177	      var request = privateSaleApi.notifyCarIsSold(reason);
3178
3179	      updateUIForPopupForm(request, 'soldMyCar');
3180	    },
3181	    errorPlacement: function(error, element) {
3182	      var name = element.attr('name');
3183
3184	      if (element.attr('name') === 'reason') {
3185	        return error.insertAfter('#sold-my-car-reason');
3186	      }
3187
3188	      error.insertAfter(element);
3189	    }
3190	  });
3191	}
3192
3193	/**
3194	 * Initialize the functionality of the
3195	 * user menu dropdown from the page header
3196	 */
3197	function initHeaderMenu() {
3198	  var $popup = $('#private-sale-login-menu-popup');
3199	  var $trigger = $('#private-sale-login-menu-trigger');
3200	  var $userNamePlaceholder = $('#private-sale-login-menu-user-name');
3201	  var $userEmailPlaceholder = $('#private-sale-login-menu-user-email');
3202	  var userName = $('#private-sale-sidebar-user-name').text();
3203	  var userEmail = $('#private-sale-sidebar-user-email').text();
3204
3205	  // Use this class to make it visible or not in the DOM.
3206	  var visibilityClass = 'is-visible';
3207
3208	  // Rely on variable not in DOM to determine
3209	  // whether it's visible or not.
3210	  var isVisible = false;
3211
3212	  // Fill user name and email in the header popup menu
3213	  $userNamePlaceholder.html(userName);
3214	  $userEmailPlaceholder.html(userEmail);
3215
3216	  // Fill user email in the link that triggers the
3217	  // header popup menu
3218	  $('#private-sale-login-menu-email').html(userEmail);
3219
3220	  function showPopup() {
3221	      // prevent attaching the listener multiple times
3222	      if (!isVisible) {
3223	          // make it visible in the DOM
3224	          $popup.addClass(visibilityClass);
3225	          // attach listener to hidepopup on click body
3226	          // notice adding 'clickable' class name to prevent issue on iOS
3227	          $('body').addClass('clickable').on('click', hidePopup);
3228	          // make it visible in the logic
3229	          isVisible = true;
3230	      }
3231	  };
3232
3233	  function hidePopup() {
3234	      if (isVisible) {
3235	          // make it not visible in the DOM
3236	          $popup.removeClass(visibilityClass);
3237	          // detach listener to hidepopup on click body
3238	          // notice removing 'clickable' class name which was added to prevent issue on iOS
3239	          $('body').removeClass('clickable').off('click', hidePopup);
3240	          // ake it not visible in the logic
3241	          isVisible = false;
3242	      }
3243	  }
3244
3245	  // This fn hides the main menu of the page on small screens
3246	  // This won't work if [data-navigation-menu] is not there
3247	  function hidePageMobileMenu() {
3248	      $('[data-navigation-menu] > div').addClass('hide');
3249	  }
3250
3251	  // Listen click to trigger link.
3252	  $trigger.on('click', function(event) {
3253	      event.preventDefault();
3254	      // Stop propagation to body so it doesn't hide the popup.
3255	      event.stopPropagation();
3256	      // Toggle the popup
3257	      if (isVisible) {
3258	        hidePopup()
3259	      } else {
3260	        showPopup();
3261	      }
3262	  });
3263
3264	  // Listen click to navigation popup links.
3265	  $popup.on('click', 'a', function() {
3266	      // Hide popup when navigating
3267	      hidePopup();
3268	      // and close mobile menu.
3269	      hidePageMobileMenu();
3270	  });
3271
3272	  // Listen click to the popup box.
3273	  $popup.on('click', function(event) {
3274	      // Stop propagation to body so it doesn't hide the popup.
3275	      // This won't affect clicking the links since they have an
3276	      // event listener that takes care of hiding the popup.
3277	      event.stopPropagation();
3278	  });
3279	}
3280
3281	/**
3282	 * Initialize the functionality
3283	 * of the Comments form
3284	 */
3285	function initCommentsForm() {
3286	  UI.comments.form.validate({
3287	    rules: {
3288	      max: 500
3289	    },
3290	    onfocusout: false,
3291	    onkeyup: false,
3292	    onclik: false,
3293	    submitHandler: function() {
3294	      var comments = DOM.getFieldValue(UI.comments.form, 'comments');
3295	      var request = privateSaleApi.updateComments(comments);
3296
3297	      updateUI(request, 'comments');
3298	    }
3299	  });
3300	}
3301
3302	/**
3303	 * Initialize the functionality
3304	 * of the Testdrive form
3305	 */
3306	function initTestdriveForm() {
3307	  var form = UI.testdrive.form;
3308
3309	  form.validate({
3310	    rules: {
3311	      'hours': 'required'
3312	    },
3313	    errorPlacement: function(error, element) {
3314	      var fieldName = element.attr('name');
3315
3316	      if (fieldName === 'hours') {
3317	        return error.insertAfter('#testdrive-hours');
3318	      }
3319
3320	      error.insertAfter(element);
3321	    },
3322	    submitHandler: function() {
3323	      var days = DOM.getFieldValue(form, 'days');
3324	      var hours = DOM.getFieldValue(form, 'hours', true);
3325
3326	      var request = privateSaleApi.updateTestDriveAvailability(days, hours);
3327
3328	      updateUI(request, 'testdrive');
3329	    },
3330	    showErrors: onShowErrors('testdrive')
3331	  })
3332	}
3333
3334	/**
3335	 * Initialize the functionality
3336	 * of the Others form
3337	 */
3338	function initOthersForm() {
3339	  var form = UI.others.form;
3340
3341	  form.validate({
3342	    rules: {
3343	      phoneNumber: {
3344	        required: true,
3345	        digits: true
3346	      },
3347	      minimumPrice: {
3348	        required: false,
3349	        number: true,
3350	        digits: true,
3351	      }
3352	    },
3353	    submitHandler: function() {
3354	      var phoneNumber = Number(DOM.getFieldValue(form, 'phoneNumber'));
3355	      var phoneCode = DOM.getFieldValue(form, 'phoneCode');
3356	      var minimumPrice = Number(DOM.getFieldValue(form, 'minimumPrice'));
3357	      
3358	      var request = privateSaleApi.updateOtherData(phoneCode, phoneNumber, minimumPrice);
3359
3360	      request.done(function() {
3361	        var callMeBackForm = UI.callMeBack.form;
3362
3363	        sharedData.phoneNumber = phoneNumber;
3364	        sharedData.phoneCode = phoneCode;
3365
3366	        DOM.setFieldValue(callMeBackForm, 'phoneNumber', phoneNumber);
3367	        DOM.setFieldValue(callMeBackForm, 'phoneCode', phoneCode);
3368	      });
3369
3370	      updateUI(request, 'others');
3371	    },
3372	    errorPlacement: function(error, element) {
3373	      if (element.attr('name') === 'phoneNumber') {
3374	        return error.insertAfter('#others-phone');
3375	      }
3376
3377	      if (element.attr('name') === 'minimumPrice') {
3378	        return error.insertAfter('#others-minimum-price');
3379	      }
3380
3381	      error.insertAfter(element);
3382	    },
3383	    showErrors: onShowErrors('others')
3384	  })
3385	}
3386
3387	/**
3388	 * Initialize the functionality
3389	 * of the sticky sidebar
3390	 */
3391	function initSidebar() {
3392	  // Get the sidebar once
3393	  var $sidebar = $('#private-sale-dashboard-sidebar');
3394
3395	  // init the sidebar if it is visible so we
3396	  // get the right top offset instead of 0
3397	  if ($sidebar.is(':visible')) {
3398	    initSidebarFixedBehavior();
3399	  } else {
3400	    // Otherwise listen to resize event
3401	    $(window).on('resize', onWindowResize);
3402	  }
3403
3404	  // it updates the sidebar position once
3405	  // and listens to window scroll for updating
3406	  // the sidebar position again
3407	  function initSidebarFixedBehavior() {
3408	    var pageBottomMargin;
3409	    var pageTopMargin = pageBottomMargin = 20;
3410
3411	    // Get its original top offset minus 20px
3412	    // so it starts the fixed behavior 20px above
3413	    // This is done in order to keep the top margin
3414	    var sidebarTopOffset = $sidebar.offset().top - pageTopMargin;
3415
3416	    updateSidebar();
3417	    $(window).scroll(updateSidebar);
3418
3419	    // it checks whether the window has scrolled
3420	    // below the sidebar top edge and based on that
3421	    // decide whether it should has a fixed
3422	    // position or not
3423	    function updateSidebar(event) {
3424	      var scrolled = $(window).scrollTop();
3425	      var contentHeight = $('#private-sale-dashboard-content').outerHeight();
3426	      var sidebarHeight = $sidebar.outerHeight();
3427
3428	      if (scrolled > sidebarTopOffset) {
3429	        $sidebar.addClass('is-fixed');
3430
3431	        // if has scrolled in such a way that the bottom of the sidebar has reached the
3432	        // bottom of the page container
3433	        if (scrolled > (sidebarTopOffset + contentHeight - sidebarHeight - pageBottomMargin - pageTopMargin)) {
3434	          // Attach the sidebar to the bottom of the main container
3435	          $sidebar
3436	            .addClass('has-reached-bottom')
3437	            .css({
3438	              bottom: (contentHeight - pageTopMargin) * -1
3439	            });
3440	        } else {
3441	          // Detach sidebar from the bottom of the container
3442	          $sidebar
3443	            .removeClass('has-reached-bottom')
3444	            .css({ bottom: 'auto' });
3445	        }
3446	      } else {
3447	        $sidebar.removeClass('is-fixed');
3448	      }
3449	    }
3450	  }
3451
3452	  // it checks whether the sidebar has
3453	  // become visible after resizing or not
3454	  function onWindowResize() {
3455	    // if it is visible now, init the behavior
3456	    if ($sidebar.is(':visible')) {
3457	      initSidebarFixedBehavior();
3458	      // then remove the listener since
3459	      // we don't need it anymore
3460	      $(window).off('resize', onWindowResize);
3461	    }
3462	  }
3463	}
3464
3465	module.exports = {
3466	  initPopUpForms: initPopUpForms,
3467	  initListingPriceForm: initListingPriceForm,
3468	  initHeaderMenu: initHeaderMenu,
3469	  initCommentsForm: initCommentsForm,
3470	  initTestdriveForm: initTestdriveForm,
3471	  initOthersForm: initOthersForm,
3472	  initSidebar: initSidebar
3473	};
3474
3475
3476/***/ }),
3477
3478/***/ 287:
3479/***/ (function(module, exports) {
3480
3481	var hiddenClassName = 'hidden';
3482
3483	/**
3484	 * Displays an element by removing the hidden
3485	 * class name from its class name list. It expects
3486	 * an object with removeClass method (such as a jQuery object).
3487	 * @param {Object} element
3488	 * @param {Function} element.removeClass
3489	 */
3490	function showElement(element) {
3491	  if (typeof element !== 'object' || typeof element.removeClass !== 'function') {
3492	    throw new TypeError('Argument element must be an object with removeClass method');
3493	  }
3494
3495	  element.removeClass(hiddenClassName);
3496	}
3497
3498	/**
3499	 * Displays an element by adding the hidden
3500	 * class name from its class name list. It expects
3501	 * an object with addClass method (such as a jQuery object).
3502	 * @param {Object} element
3503	 * @param {Function} element.addClass
3504	 */
3505	function hideElement(element) {
3506	  if (typeof element !== 'object' || typeof element.addClass !== 'function') {
3507	    throw new TypeError('Argument element must be an object with addClass method');
3508	  }
3509
3510	  element.addClass(hiddenClassName);
3511	}
3512
3513	/**
3514	 * Disables an element by adding the disabled attribute with
3515	 * value 'disbaled'. It expects an object with attr method
3516	 * (such as a jQuery object).
3517	 * @param {Object} element
3518	 * @param {Function} element.attr
3519	 */
3520	function disableElement(element) {
3521	  if (typeof element !== 'object' || typeof element.attr !== 'function') {
3522	    throw new TypeError('Argument element must be an object with attr method');
3523	  }
3524
3525	  element.attr('disabled', 'disabled');
3526	}
3527
3528	/**
3529	 * Enables an element by removing the disabled attribute.
3530	 * It expects an object with attr method (such as a jQuery object).
3531	 * @param {Object} element
3532	 * @param {Function} element.removeAttr
3533	 */
3534	function enableElement(element) {
3535	  if (typeof element !== 'object' || typeof element.removeAttr !== 'function') {
3536	    throw new TypeError('Argument element must be an object with removeAttr method');
3537	  }
3538
3539	  element.removeAttr('disabled');
3540	}
3541
3542	/**
3543	 * Disables all elements in a form.
3544	 * It expects an object with find method (such as a jQuery object).
3545	 * @param {Object} form
3546	 * @param {Function} form.find
3547	 */
3548	function disableForm(form) {
3549	  if (typeof form !== 'object' || typeof form.find !== 'function') {
3550	    throw new TypeError('Argument form must be an object with find method');
3551	  }
3552
3553	  disableElement(form.find('input, textarea, select, button'));
3554	}
3555
3556	/**
3557	 * Enables all elements in a form.
3558	 * It expects an object with find method (such as a jQuery object).
3559	 * @param {Object} form
3560	 * @param {Function} form.find
3561	 */
3562	function enableForm(form) {
3563	  if (typeof form !== 'object' || typeof form.find !== 'function') {
3564	    throw new TypeError('Argument form must be an object with find method');
3565	  }
3566
3567	  enableElement(form.find('input, textarea, select, button'));
3568	}
3569
3570	/**
3571	 * Returns the value of a field in a form
3572	 * @param {Object} form A jQuery object wrapping a form
3573	 * @param {string} fieldName The name of the field from which the value is going to be retrieved
3574	 * @param {Boolean} isCheckboxList A boolean value which indicates whether the field is a list of checkbox or not
3575	 * @return {string}
3576	 */
3577	function getFieldValue(form, fieldName, isCheckboxList) {
3578	  if (form[0][fieldName] === undefined) {
3579	    throw new Error('Field ' + fieldName + ' does not exist in the form');
3580	  }
3581
3582	  var field = form[0][fieldName];
3583
3584	  if (isCheckboxList === true) {
3585	    return Array.from(field).reduce(function(acc, current) {
3586	      if (current.checked) {
3587	        return acc.concat(current.value);
3588	      }
3589	      return acc;
3590	    }, []);
3591	  }
3592
3593	  return field.value;
3594	}
3595
3596	/**
3597	 * Sets the value of a field in a form
3598	 * @param {Object} form A jQuery object wrapping a form
3599	 * @param {string} fieldName The name of the field to which the value is going to be set
3600	 * @param {string|number} value The value to be set in the field
3601	 */
3602	function setFieldValue(form, fieldName, value) {
3603	  if (form[0][fieldName] === undefined) {
3604	    throw new Error('Field ' + fieldName + ' does not exist in the form');
3605	  }
3606	  form[0][fieldName].value = value;
3607	}
3608
3609	module.exports = {
3610	  hideElement: hideElement,
3611	  showElement: showElement,
3612	  enableElement: enableElement,
3613	  disableElement: disableElement,
3614	  getFieldValue: getFieldValue,
3615	  setFieldValue: setFieldValue,
3616	  enableForm: enableForm,
3617	  disableForm: disableForm
3618	};
3619
3620
3621/***/ }),
3622
3623/***/ 288:
3624/***/ (function(module, exports) {
3625
3626	/**
3627	 * Returns a string representation of a full URL
3628	 * @param {String} path String that indicates the path to the resource
3629	 * @throws {TypeError}
3630	 */
3631	function makeUrl(path) {
3632	  if (typeof path !== 'string') {
3633	    throw new TypeError('Argument path must be an string');
3634	  }
3635
3636	  return window.location.pathname + path + '/';
3637	}
3638
3639	/**
3640	 * Makes a post request to the specified path with the specified data and callbacks
3641	 * @param {String} path String that indicates the path to the resource
3642	 * @param {any} data The data that is sent to the server
3643	 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR)
3644	 * @throws {TypeError}
3645	 */
3646	function post(path, data) {
3647	  if (typeof path !== 'string') {
3648	    throw new TypeError('Argument path must be an string');
3649	  }
3650
3651	  var url = makeUrl(path);
3652	  var request = $.post(url, data);
3653
3654	  return request;
3655	}
3656
3657	/**
3658	 * Updates the listing price in the server
3659	 * @param {Number} price An integer value
3660	 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR)
3661	 * @throws {TypeError}
3662	 */
3663	function updateListingPrice(price) {
3664	  if (!Number.isInteger(price)) {
3665	    throw new TypeError('Argument price must be an integer number');
3666	  }
3667
3668	  var data = { price: price };
3669
3670	  return post('listing-price', data);
3671	}
3672
3673	/**
3674	 * Requests a call to the user phone
3675	 * @param {String} reason A string which value might be one of: 'modification', 'error', 'removal' or 'other'
3676	 * @param {String} phoneCode A non empty string value
3677	 * @param {Number} phoneNumber An integer value
3678	 * @param {String} otherReasonDetails A string value. It's required only if reason argument is 'other'
3679	 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR)
3680	 * @throws {TypeError}
3681	 */
3682	function requestACall(reason, phoneCode, phoneNumber, otherReasonDetails) {
3683	  var validReasons = ['modification', 'error', 'removal', 'other'];
3684
3685	  if (validReasons.indexOf(reason) < 0) {
3686	    throw new TypeError('Argument reason must be one of ' + validReasons.join(', '));
3687	  }
3688
3689	  if (typeof phoneCode !== 'string' || phoneCode.trim() === '') {
3690	    throw new TypeError('Argument phoneCode must be a non-empty string');
3691	  }
3692
3693	  if (!Number.isInteger(phoneNumber)) {
3694	    throw new TypeError('Argument phoneNumber must be an integer number');
3695	  }
3696
3697	  if (reason === 'other') {
3698	    if (typeof otherReasonDetails !== 'string' || otherReasonDetails.trim() === '') {
3699	      throw new TypeError('Argument otherReasonDetails must be a non empty string value if argument reason is \`empty\`'); 
3700	    }
3701	  }
3702
3703	  var data = {
3704	    reason: reason,
3705	    phoneCode: phoneCode,
3706	    phoneNumber: phoneNumber
3707	  };
3708
3709	  // Only add the 'other' reason details if reason is 'other'
3710	  if (reason === 'other') {
3711	    data.otherReasonDetails = otherReasonDetails;
3712	  }
3713
3714	  return post('call-me-back', data);
3715	}
3716
3717	/**
3718	 * Notify the car has been sold
3719	 * @param {String} detail A string which value might be one of: 'testdrive', 'private', 'dealer' or 'keep'
3720	 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR)
3721	 * @throws {TypeError}
3722	 */
3723	function notifyCarIsSold(detail) {
3724	  var validDetails = ['testdrive', 'private', 'dealer', 'keep'];
3725
3726	  if (validDetails.indexOf(detail) < 0) {
3727	    throw new TypeError('Argument detail must be one of ' + validDetails.join(', '));
3728	  }
3729
3730	  var data = { detail: detail };
3731
3732	  return post('sold-car', data);
3733	}
3734
3735	/**
3736	 * Updates the availability for the test drive in the server
3737	 * @param {String} days A string which value might be one of: 'anyday', 'weekdays' or 'weekend'
3738	 * @param {String[]} hours An array of strings which values might be one of: 'morning', 'midday', 'afternoon' or 'evening'.
3739	 * Each value must not exist more than once inside the array.
3740	 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR)
3741	 * @throws {TypeError}
3742	 */
3743	function updateTestDriveAvailability(days, hours) {
3744	  var validDays = ['anyday', 'weekdays', 'weekend'];
3745	  var validHours = ['morning', 'midday', 'afternoon', 'evening'];
3746	  var uniqueHours = [];
3747
3748	  if (validDays.indexOf(days) < 0) {
3749	    throw new TypeError('Argument days must be one of ' + validDays.join(', '));
3750	  }
3751
3752	  if (!Array.isArray(hours)) {
3753	    throw new TypeError('Argument hours must be an array');
3754	  }
3755
3756	  hours.forEach(function(hour) {
3757	    if (validHours.indexOf(hour) < 0) {
3758	      throw new TypeError('Argument hours must only contain string values ' + validDays.join(', '));
3759	    }
3760
3761	    if (uniqueHours.indexOf(hour) >= 0) {
3762	      throw new TypeError('Argument hours must contain unique values. Found value ' + hour + ' more than once.');
3763	    }
3764
3765	    uniqueHours.push(hour);
3766	  });
3767
3768	  var data = {
3769	    days: days,
3770	    hours: uniqueHours
3771	  };
3772
3773	  return post('test-drive', data);
3774	}
3775
3776	/**
3777	 * Updates comments about the car in the server
3778	 * @param {String} comments A string which length must be less than 500
3779	 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR)
3780	 * @throws {TypeError}
3781	 */
3782	function updateComments(comments) {
3783	  if (typeof comments !== 'string' || comments.length > 500) {
3784	    throw new TypeError('Argument comments must be a string value which length must be less than 500');
3785	  }
3786
3787	  var data = { comments: comments };
3788
3789	  return post('comments', data);
3790	}
3791
3792	/**
3793	 * Updates additional information related to the private sale
3794	 * @param {String} phoneCode A non-empty string
3795	 * @param {Number} phoneNumber An integer value
3796	 * @param {Number} minimumPrice An integer value
3797	 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR)
3798	 * @throws {TypeError}
3799	 */
3800	function updateOtherData(phoneCode, phoneNumber, minimumPrice) {
3801	  if (typeof phoneCode !== 'string' || phoneCode.trim() === '') {
3802	    throw new TypeError('Argument phoneCode must be a non-empty string');
3803	  }
3804
3805	  if (!Number.isInteger(phoneNumber)) {
3806	    throw new TypeError('Argument phoneNumber must be an integer number');
3807	  }
3808
3809	  if (!Number.isInteger(minimumPrice)) {
3810	    throw new TypeError('Argument minimumPrice must be an integer number');
3811	  }
3812
3813	  var data = {
3814	    phoneCode: phoneCode,
3815	    phoneNumber: phoneNumber,
3816	    minimumPrice: minimumPrice
3817	  };
3818
3819	  return post('other', data);
3820	}
3821
3822	module.exports = {
3823	  updateListingPrice: updateListingPrice,
3824	  requestACall: requestACall,
3825	  notifyCarIsSold: notifyCarIsSold,
3826	  updateTestDriveAvailability: updateTestDriveAvailability,
3827	  updateComments: updateComments,
3828	  updateOtherData: updateOtherData
3829	};
3830
3831
3832/***/ }),
3833
3834/***/ 289:
3835/***/ (function(module, exports, __webpack_require__) {
3836
3837	/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["faqTabsModule"] = __webpack_require__(290);
3838	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
3839
3840/***/ }),
3841
3842/***/ 290:
3843/***/ (function(module, exports) {
3844
3845	var faqTabsModule = module.exports = function () {
3846	    var prefix = '.faq-tabs';
3847
3848	    function initialize() {
3849	        // Hide all content, all answers and all close icons
3850	        selector('content').hide();
3851	        selector('question-answer').hide();
3852	        selector('close-question').hide();
3853
3854	        replaceAllSvgs();
3855	        setCategorySelectors();
3856	        setSubcategorySelectors();
3857	        setQuestionSelectors();
3858	        selectCategory(getFirstCategory().attr('data-category-id'));
3859	    }
3860
3861	    function replaceWithInlineSvg(imgURL, $img) {
3862	        var imgID = $img.attr('id');
3863	        var imgClass = $img.attr('class');
3864
3865	        $.get(imgURL, function(data) {
3866	            // Get the SVG tag, ignore the rest
3867	            var $svg = $(data).find('svg');
3868	            // Add replaced image's ID to the new SVG
3869	            if(typeof imgID !== 'undefined') {
3870	                $svg = $svg.attr('id', imgID);
3871	            }
3872	            // Add replaced image's classes to the new SVG
3873	            if(typeof imgClass !== 'undefined') {
3874	                $svg = $svg.attr('class', imgClass + ' replaced-svg');
3875	            }
3876	            // Remove any invalid XML tags as per http://validator.w3.org
3877	            $svg = $svg.removeAttr('xmlns:a');
3878	            // Replace image with new SVG
3879	            $img.replaceWith($svg);
3880	        }, 'xml');
3881	    }
3882
3883	    // Replace categories and subcategories icons with inline SVGs so we can change color on active
3884	    function replaceAllSvgs() {
3885	        var svgImgSelectors = prefix + ' img[data-src]';
3886
3887	        $(svgImgSelectors).each(function() {
3888	            var $img = $(this);
3889	            var imgURL = $img.attr('data-src');
3890	            var ext = imgURL.split('.').pop().toLowerCase();
3891
3892	            if(ext === 'svg') {
3893	                replaceWithInlineSvg(imgURL, $img);
3894	            } else {
3895	                $img.attr('src', imgURL);
3896	            }
3897	        });
3898	    }
3899
3900	    function selector(className) {
3901	        return $(prefix + '__' + className);
3902	    }
3903
3904	    function categoryAttrSelector(className, categoryId) {
3905	        return $(prefix + '__' + className + '[data-category-id=\'' + categoryId + '\']');
3906	    }
3907
3908	    function subcategoryAttrSelector(className, subcategoryId) {
3909	        return $(prefix + '__' + className + '[data-subcategory-id=\'' + subcategoryId + '\']');
3910	    }
3911
3912	    function selectFirstSubcategory(categoryId) {
3913	        var $subcategory = getFirstSubcategory(categoryId);
3914	        if($subcategory) {
3915	            // Select first subcategory
3916	            selectSubcategory($subcategory.attr('data-subcategory-id'));
3917	        } else {
3918	            // no subcategories then hide the arrow
3919	            selector('subcategory-arrow').hide();
3920	        }
3921	    }
3922
3923	    function getSelectedCategoryId() {
3924	        var $selectedCategory = selector('category.active-category');
3925	        if($selectedCategory) {
3926	            return $selectedCategory.attr('data-category-id');
3927	        }
3928	    }
3929
3930	    function selectCategory(categoryId) {
3931	        // De-activate all categories except the one selected
3932	        selector('category').removeClass('active-category');
3933	        categoryAttrSelector('category', categoryId).addClass('active-category');
3934	        // Hide all content and show content by selected category
3935	        selector('content').hide();
3936	        categoryAttrSelector('content', categoryId).show();
3937	        // Hide all subcategories dropdown and show the one that matches the selected category
3938	        selector('subcategories').css('display', 'none');
3939	        categoryAttrSelector('subcategories', categoryId).css('display', 'flex');
3940	        //
3941	        selectFirstSubcategory(categoryId);
3942	    }
3943
3944	    function selectSubcategory(subcategoryId) {
3945	        var $subcategory = subcategoryAttrSelector('subcategory', subcategoryId);
3946	        // Make sure subcategories arrow is shown
3947	        var $subcategoryArrow = selector('subcategory-arrow');
3948	        $subcategoryArrow.show();
3949	        // De-activate all subcategories and activate current selected subcategory
3950	        selector('subcategory').removeClass('active-subcategory');
3951	        $subcategory.addClass('active-subcategory');
3952	        // Animated subcategories arrow to the selected subcategory
3953	        var centerPoint = ($subcategory.width() / 2) - ($subcategoryArrow.width() / 2);
3954	        var newLeft = centerPoint + $subcategory.position().left;
3955	        $subcategoryArrow.animate({
3956	            'left': newLeft
3957	        });
3958	    }
3959
3960	    function getFirstCategory() {
3961	        var $category = selector('category');
3962	        if ($category.length) {
3963	            return $category.first();
3964	        }
3965	    }
3966
3967	    function getFirstSubcategory(categoryId) {
3968	        var $subcategories = categoryAttrSelector('subcategories', categoryId);
3969	        // if subcategories exist for this category
3970	        if ($subcategories.length) {
3971	            return $subcategories.find(prefix + '__subcategory').first();
3972	        }
3973	    }
3974
3975	    function jumpToSubcategory(subcategoryId) {
3976	        var $jumpEle = $(prefix + ' h3[name=\'subcategory-' + subcategoryId + '\']');
3977	        if($jumpEle.length) {
3978	            $('html, body').animate({
3979	                scrollTop: $jumpEle.offset().top
3980	            }, 500);
3981	        }
3982	    }
3983
3984	    function setCategorySelectors() {
3985	        selector('category').click(function(event) {
3986				event.preventDefault();
3987	            selectCategory($(this).attr('data-category-id'));
3988	        });
3989	    }
3990
3991	    function setSubcategorySelectors() {
3992	        $(prefix + '__subcategory').click(function(event) {
3993				event.preventDefault();
3994	            var subcategoryId = $(this).attr('data-subcategory-id');
3995	            selectSubcategory(subcategoryId);
3996	            jumpToSubcategory(subcategoryId);
3997	        });
3998	    }
3999
4000	    function setQuestionSelectors() {
4001	        $(prefix + '__question-title').click(function(event) {
4002				event.preventDefault();
4003	            var $answer = $(this).next(prefix + '__question-answer');
4004	            var $openIcon = $(this).find(prefix + '__open-question');
4005	            var $closeIcon = $(this).find(prefix + '__close-question');
4006	            // Toggle answer
4007	            if($answer.is(":visible")) {
4008	                $answer.slideUp('fast');
4009	                $openIcon.show();
4010	                $closeIcon.hide();
4011	                $(this).removeClass('active-question');
4012	            } else {
4013	                $answer.slideDown('fast');
4014	                $openIcon.hide();
4015	                $closeIcon.show();
4016	                $(this).addClass('active-question');
4017	            }
4018	        });
4019	    }
4020
4021	    return {
4022	        initialize: initialize
4023	    };
4024	}();
4025
4026
4027/***/ }),
4028
4029/***/ 291:
4030/***/ (function(module, exports) {
4031
4032	/**
4033	 * Created by alexz on 18.11.16.
4034	 */
4035
4036	;(function($) {
4037	  'use strict';
4038
4039	  var __debug = false;
4040	  var cityModify = {isChanged: false, value: ''};
4041
4042	  var makePUTRequest = function(data, carHash) {
4043	    $.ajax({
4044	      url: '/papi/v1/car-details/marketing-property/' + carHash,
4045	      beforeSend: function(xhr) {
4046	        xhr.overrideMimeType( "application/json; charset=utf-8" );
4047	      },
4048	      type: 'PUT',
4049	      dataType: 'json',
4050	      contentType: "application/json; charset=utf-8",
4051	      headers: {'Content-Type': 'application/json'},
4052	      data: JSON.stringify(data),
4053	      success: function(result) {
4054	        if (__debug) console.log(result);
4055	      }
4056	    });
4057	  };
4058
4059	  var checkIfCityModified = function(city) {
4060	    if (!cityModify.value.length) {
4061	      cityModify.value = city;
4062	    } else if (cityModify.value !== city) {
4063	      cityModify.isChanged = true;
4064	    }
4065	  };
4066
4067	  var constructRequest = function(e, valueIndex) {
4068	    var result = {};
4069	    var propertyMap = {
4070	      city: 3401,
4071	      branch: 3402,
4072	      date: 3403,
4073	      time: 3404,
4074	      fname: 3405,
4075	      lname: 3406,
4076	      telephone: 3407,
4077	      interestedIn: 3408
4078	    };
4079
4080	    if (
4081	        e.attr('class') == 'branches-ini-item' &&
4082	        e[0].hasAttribute('data-city')
4083	    ){
4084	      result.propertyId = 3401;
4085	      result.value = e.attr('data-city');
4086	      checkIfCityModified(e.attr('data-city'));
4087	    } else {
4088	      result.propertyId = propertyMap[
4089	          e.attr('name') == "mobile[number]" ?
4090	              'telephone' :
4091	              e.attr('name')];
4092
4093	      result.value = e.is('select') ?
4094	          e.attr('name') == 'time' ?
4095	              e.find('option:selected').text() :
4096	              e.val()
4097	          : valueIndex;
4098	    }
4099
4100	    return result;
4101	  };
4102
4103	  var sendData = function(e) {
4104	    if (e.isTrigger) return;
4105
4106	    var $this = $(this);
4107
4108	    if (!$this.val()) return;
4109
4110	    var valueIndex = $this.val().length ? 1 : 0;
4111
4112	    if (
4113	        $('#carHash').val().length &&
4114	        $this.attr('id') != "inpulect" &&
4115	        $this.attr('name') != "mobile[prefix]"
4116	    ) {
4117
4118	      if (__debug) console.log(constructRequest($this, valueIndex));
4119
4120	      makePUTRequest(constructRequest($this, valueIndex), $('#carHash').val());
4121	    }
4122	  };
4123
4124	  var sendCustomSelectData = function() {
4125	    if (__debug) console.log(constructRequest($(this)));
4126
4127	    makePUTRequest(constructRequest($(this)), $('#carHash').val());
4128	  };
4129
4130	  var sendBranchData = function(e) {
4131	    if (!cityModify.isChanged && e.isTrigger) return;
4132
4133	    var result = {};
4134	    result.propertyId = 3402;
4135	    result.value = $(this).attr('data-id');
4136
4137	    if (__debug) console.log(result);
4138
4139	    makePUTRequest(result, $('#carHash').val());
4140	  };
4141
4142	  function sendCity(e){
4143	    var request = {};
4144
4145	    if (e.keyCode == 13) {
4146	      request.propertyId = 3401;
4147	      request.value = e.currentTarget.value;
4148
4149	      if (__debug) console.log(e,
4150	          e.currentTarget,
4151	          e.currentTarget.value,
4152	          'request data is: ',
4153	          request
4154	      );
4155	      checkIfCityModified(e.currentTarget.value);
4156	      makePUTRequest(request, $('#carHash').val());
4157	    }
4158	  }
4159
4160	  /**
4161	   * @param delay - a provide of debug value - is true or false.
4162	   * @example $appointmentForm.trackUserData(true);
4163	   * @returns {jQueryElement}
4164	   */
4165
4166	  $.fn.trackUserData = function(debugingValue) {
4167	    var $this = $(this);
4168	    __debug = debugingValue;
4169
4170	    $this.on('click', '#branches', sendData);
4171	    $this.on('click', '.branch', sendBranchData);
4172	    $this.find('select:visible').on('change', sendData);
4173	    $this.find('input[type=text]:visible').on('blur', sendData);
4174	    $this.find('input[type=text]').on('keyup', sendCity);
4175	    $('div.branches-ini-item').on('click', sendCustomSelectData);
4176
4177	    return $this;
4178	  };
4179
4180	})(jQuery);
4181
4182
4183/***/ }),
4184
4185/***/ 299:
4186/***/ (function(module, exports) {
4187
4188	;(function($) {
4189	  'use strict';
4190
4191	  $.fn.callmeDatetimeFilter = function(cache) {
4192	    var $this = $(this);
4193	    var $selectedDay = new Date($('select#days.form-control').find(':selected').val());
4194	    var timeNow = new Date();
4195
4196	    $this.prop('selectedIndex', 0);
4197
4198	    if ($selectedDay.getDay() !== timeNow.getDay()) {
4199	      $this.empty().append(cache);
4200	      $this.prop('selectedIndex', 0);
4201	      return;
4202	    }
4203
4204	    $this.find('option').each(function() {
4205	      var $option = $(this);
4206	      var optTime = $option.val().split(':')[0];
4207
4208	      if (optTime <= timeNow.getHours()) {
4209	        $option.remove();
4210	      }
4211	    });
4212
4213	    $this.find('optgroup').each(function() {
4214	      var hideOptGroup = false;
vendor: 20,844 bytes, lines 4215-4875
4215	      var $this = $(this);
4216
4217	      if ($this.find('option').length < 1) {
4218	        $this.remove();
4219	      }
4220	    });
4221
4222	    return $this;
4223	  }
4224	})(jQuery);
4225
4226
4227/***/ }),
4228
4229/***/ 314:
4230/***/ (function(module, exports) {
4231
4232	/* ========================================================================
4233	 * Bootstrap: tooltip.js v3.3.7
4234	 * http://getbootstrap.com/javascript/#tooltip
4235	 * Inspired by the original jQuery.tipsy by Jason Frame
4236	 * ========================================================================
4237	 * Copyright 2011-2016 Twitter, Inc.
4238	 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
4239	 * ======================================================================== */
4240
4241
4242	+function ($) {
4243	  'use strict';
4244
4245	  // TOOLTIP PUBLIC CLASS DEFINITION
4246	  // ===============================
4247
4248	  var Tooltip = function (element, options) {
4249	    this.type       = null
4250	    this.options    = null
4251	    this.enabled    = null
4252	    this.timeout    = null
4253	    this.hoverState = null
4254	    this.$element   = null
4255	    this.inState    = null
4256
4257	    this.init('tooltip', element, options)
4258	  }
4259
4260	  Tooltip.VERSION  = '3.3.7'
4261
4262	  Tooltip.TRANSITION_DURATION = 150
4263
4264	  Tooltip.DEFAULTS = {
4265	    animation: true,
4266	    placement: 'top',
4267	    selector: false,
4268	    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
4269	    trigger: 'hover focus',
4270	    title: '',
4271	    delay: 0,
4272	    html: false,
4273	    container: false,
4274	    viewport: {
4275	      selector: 'body',
4276	      padding: 0
4277	    }
4278	  }
4279
4280	  Tooltip.prototype.init = function (type, element, options) {
4281	    this.enabled   = true
4282	    this.type      = type
4283	    this.$element  = $(element)
4284	    this.options   = this.getOptions(options)
4285	    this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
4286	    this.inState   = { click: false, hover: false, focus: false }
4287
4288	    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
4289	      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
4290	    }
4291
4292	    var triggers = this.options.trigger.split(' ')
4293
4294	    for (var i = triggers.length; i--;) {
4295	      var trigger = triggers[i]
4296
4297	      if (trigger == 'click') {
4298	        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
4299	      } else if (trigger != 'manual') {
4300	        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
4301	        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
4302
4303	        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
4304	        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
4305	      }
4306	    }
4307
4308	    this.options.selector ?
4309	      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
4310	      this.fixTitle()
4311	  }
4312
4313	  Tooltip.prototype.getDefaults = function () {
4314	    return Tooltip.DEFAULTS
4315	  }
4316
4317	  Tooltip.prototype.getOptions = function (options) {
4318	    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
4319
4320	    if (options.delay && typeof options.delay == 'number') {
4321	      options.delay = {
4322	        show: options.delay,
4323	        hide: options.delay
4324	      }
4325	    }
4326
4327	    return options
4328	  }
4329
4330	  Tooltip.prototype.getDelegateOptions = function () {
4331	    var options  = {}
4332	    var defaults = this.getDefaults()
4333
4334	    this._options && $.each(this._options, function (key, value) {
4335	      if (defaults[key] != value) options[key] = value
4336	    })
4337
4338	    return options
4339	  }
4340
4341	  Tooltip.prototype.enter = function (obj) {
4342	    var self = obj instanceof this.constructor ?
4343	      obj : $(obj.currentTarget).data('bs.' + this.type)
4344
4345	    if (!self) {
4346	      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
4347	      $(obj.currentTarget).data('bs.' + this.type, self)
4348	    }
4349
4350	    if (obj instanceof $.Event) {
4351	      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
4352	    }
4353
4354	    if (self.tip().hasClass('in') || self.hoverState == 'in') {
4355	      self.hoverState = 'in'
4356	      return
4357	    }
4358
4359	    clearTimeout(self.timeout)
4360
4361	    self.hoverState = 'in'
4362
4363	    if (!self.options.delay || !self.options.delay.show) return self.show()
4364
4365	    self.timeout = setTimeout(function () {
4366	      if (self.hoverState == 'in') self.show()
4367	    }, self.options.delay.show)
4368	  }
4369
4370	  Tooltip.prototype.isInStateTrue = function () {
4371	    for (var key in this.inState) {
4372	      if (this.inState[key]) return true
4373	    }
4374
4375	    return false
4376	  }
4377
4378	  Tooltip.prototype.leave = function (obj) {
4379	    var self = obj instanceof this.constructor ?
4380	      obj : $(obj.currentTarget).data('bs.' + this.type)
4381
4382	    if (!self) {
4383	      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
4384	      $(obj.currentTarget).data('bs.' + this.type, self)
4385	    }
4386
4387	    if (obj instanceof $.Event) {
4388	      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
4389	    }
4390
4391	    if (self.isInStateTrue()) return
4392
4393	    clearTimeout(self.timeout)
4394
4395	    self.hoverState = 'out'
4396
4397	    if (!self.options.delay || !self.options.delay.hide) return self.hide()
4398
4399	    self.timeout = setTimeout(function () {
4400	      if (self.hoverState == 'out') self.hide()
4401	    }, self.options.delay.hide)
4402	  }
4403
4404	  Tooltip.prototype.show = function () {
4405	    var e = $.Event('show.bs.' + this.type)
4406
4407	    if (this.hasContent() && this.enabled) {
4408	      this.$element.trigger(e)
4409
4410	      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
4411	      if (e.isDefaultPrevented() || !inDom) return
4412	      var that = this
4413
4414	      var $tip = this.tip()
4415
4416	      var tipId = this.getUID(this.type)
4417
4418	      this.setContent()
4419	      $tip.attr('id', tipId)
4420	      this.$element.attr('aria-describedby', tipId)
4421
4422	      if (this.options.animation) $tip.addClass('fade')
4423
4424	      var placement = typeof this.options.placement == 'function' ?
4425	        this.options.placement.call(this, $tip[0], this.$element[0]) :
4426	        this.options.placement
4427
4428	      var autoToken = /\s?auto?\s?/i
4429	      var autoPlace = autoToken.test(placement)
4430	      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
4431
4432	      $tip
4433	        .detach()
4434	        .css({ top: 0, left: 0, display: 'block' })
4435	        .addClass(placement)
4436	        .data('bs.' + this.type, this)
4437
4438	      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
4439	      this.$element.trigger('inserted.bs.' + this.type)
4440
4441	      var pos          = this.getPosition()
4442	      var actualWidth  = $tip[0].offsetWidth
4443	      var actualHeight = $tip[0].offsetHeight
4444
4445	      if (autoPlace) {
4446	        var orgPlacement = placement
4447	        var viewportDim = this.getPosition(this.$viewport)
4448
4449	        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :
4450	                    placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :
4451	                    placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :
4452	                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :
4453	                    placement
4454
4455	        $tip
4456	          .removeClass(orgPlacement)
4457	          .addClass(placement)
4458	      }
4459
4460	      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
4461
4462	      this.applyPlacement(calculatedOffset, placement)
4463
4464	      var complete = function () {
4465	        var prevHoverState = that.hoverState
4466	        that.$element.trigger('shown.bs.' + that.type)
4467	        that.hoverState = null
4468
4469	        if (prevHoverState == 'out') that.leave(that)
4470	      }
4471
4472	      $.support.transition && this.$tip.hasClass('fade') ?
4473	        $tip
4474	          .one('bsTransitionEnd', complete)
4475	          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
4476	        complete()
4477	    }
4478	  }
4479
4480	  Tooltip.prototype.applyPlacement = function (offset, placement) {
4481	    var $tip   = this.tip()
4482	    var width  = $tip[0].offsetWidth
4483	    var height = $tip[0].offsetHeight
4484
4485	    // manually read margins because getBoundingClientRect includes difference
4486	    var marginTop = parseInt($tip.css('margin-top'), 10)
4487	    var marginLeft = parseInt($tip.css('margin-left'), 10)
4488
4489	    // we must check for NaN for ie 8/9
4490	    if (isNaN(marginTop))  marginTop  = 0
4491	    if (isNaN(marginLeft)) marginLeft = 0
4492
4493	    offset.top  += marginTop
4494	    offset.left += marginLeft
4495
4496	    // $.fn.offset doesn't round pixel values
4497	    // so we use setOffset directly with our own function B-0
4498	    $.offset.setOffset($tip[0], $.extend({
4499	      using: function (props) {
4500	        $tip.css({
4501	          top: Math.round(props.top),
4502	          left: Math.round(props.left)
4503	        })
4504	      }
4505	    }, offset), 0)
4506
4507	    $tip.addClass('in')
4508
4509	    // check to see if placing tip in new offset caused the tip to resize itself
4510	    var actualWidth  = $tip[0].offsetWidth
4511	    var actualHeight = $tip[0].offsetHeight
4512
4513	    if (placement == 'top' && actualHeight != height) {
4514	      offset.top = offset.top + height - actualHeight
4515	    }
4516
4517	    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
4518
4519	    if (delta.left) offset.left += delta.left
4520	    else offset.top += delta.top
4521
4522	    var isVertical          = /top|bottom/.test(placement)
4523	    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
4524	    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
4525
4526	    $tip.offset(offset)
4527	    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
4528	  }
4529
4530	  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
4531	    this.arrow()
4532	      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
4533	      .css(isVertical ? 'top' : 'left', '')
4534	  }
4535
4536	  Tooltip.prototype.setContent = function () {
4537	    var $tip  = this.tip()
4538	    var title = this.getTitle()
4539
4540	    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
4541	    $tip.removeClass('fade in top bottom left right')
4542	  }
4543
4544	  Tooltip.prototype.hide = function (callback) {
4545	    var that = this
4546	    var $tip = $(this.$tip)
4547	    var e    = $.Event('hide.bs.' + this.type)
4548
4549	    function complete() {
4550	      if (that.hoverState != 'in') $tip.detach()
4551	      if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
4552	        that.$element
4553	          .removeAttr('aria-describedby')
4554	          .trigger('hidden.bs.' + that.type)
4555	      }
4556	      callback && callback()
4557	    }
4558
4559	    this.$element.trigger(e)
4560
4561	    if (e.isDefaultPrevented()) return
4562
4563	    $tip.removeClass('in')
4564
4565	    $.support.transition && $tip.hasClass('fade') ?
4566	      $tip
4567	        .one('bsTransitionEnd', complete)
4568	        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
4569	      complete()
4570
4571	    this.hoverState = null
4572
4573	    return this
4574	  }
4575
4576	  Tooltip.prototype.fixTitle = function () {
4577	    var $e = this.$element
4578	    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
4579	      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
4580	    }
4581	  }
4582
4583	  Tooltip.prototype.hasContent = function () {
4584	    return this.getTitle()
4585	  }
4586
4587	  Tooltip.prototype.getPosition = function ($element) {
4588	    $element   = $element || this.$element
4589
4590	    var el     = $element[0]
4591	    var isBody = el.tagName == 'BODY'
4592
4593	    var elRect    = el.getBoundingClientRect()
4594	    if (elRect.width == null) {
4595	      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
4596	      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
4597	    }
4598	    var isSvg = window.SVGElement && el instanceof window.SVGElement
4599	    // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
4600	    // See https://github.com/twbs/bootstrap/issues/20280
4601	    var elOffset  = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
4602	    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
4603	    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
4604
4605	    return $.extend({}, elRect, scroll, outerDims, elOffset)
4606	  }
4607
4608	  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
4609	    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
4610	           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
4611	           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
4612	        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
4613
4614	  }
4615
4616	  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
4617	    var delta = { top: 0, left: 0 }
4618	    if (!this.$viewport) return delta
4619
4620	    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
4621	    var viewportDimensions = this.getPosition(this.$viewport)
4622
4623	    if (/right|left/.test(placement)) {
4624	      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
4625	      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
4626	      if (topEdgeOffset < viewportDimensions.top) { // top overflow
4627	        delta.top = viewportDimensions.top - topEdgeOffset
4628	      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
4629	        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
4630	      }
4631	    } else {
4632	      var leftEdgeOffset  = pos.left - viewportPadding
4633	      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
4634	      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
4635	        delta.left = viewportDimensions.left - leftEdgeOffset
4636	      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
4637	        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
4638	      }
4639	    }
4640
4641	    return delta
4642	  }
4643
4644	  Tooltip.prototype.getTitle = function () {
4645	    var title
4646	    var $e = this.$element
4647	    var o  = this.options
4648
4649	    title = $e.attr('data-original-title')
4650	      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
4651
4652	    return title
4653	  }
4654
4655	  Tooltip.prototype.getUID = function (prefix) {
4656	    do prefix += ~~(Math.random() * 1000000)
4657	    while (document.getElementById(prefix))
4658	    return prefix
4659	  }
4660
4661	  Tooltip.prototype.tip = function () {
4662	    if (!this.$tip) {
4663	      this.$tip = $(this.options.template)
4664	      if (this.$tip.length != 1) {
4665	        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
4666	      }
4667	    }
4668	    return this.$tip
4669	  }
4670
4671	  Tooltip.prototype.arrow = function () {
4672	    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
4673	  }
4674
4675	  Tooltip.prototype.enable = function () {
4676	    this.enabled = true
4677	  }
4678
4679	  Tooltip.prototype.disable = function () {
4680	    this.enabled = false
4681	  }
4682
4683	  Tooltip.prototype.toggleEnabled = function () {
4684	    this.enabled = !this.enabled
4685	  }
4686
4687	  Tooltip.prototype.toggle = function (e) {
4688	    var self = this
4689	    if (e) {
4690	      self = $(e.currentTarget).data('bs.' + this.type)
4691	      if (!self) {
4692	        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
4693	        $(e.currentTarget).data('bs.' + this.type, self)
4694	      }
4695	    }
4696
4697	    if (e) {
4698	      self.inState.click = !self.inState.click
4699	      if (self.isInStateTrue()) self.enter(self)
4700	      else self.leave(self)
4701	    } else {
4702	      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
4703	    }
4704	  }
4705
4706	  Tooltip.prototype.destroy = function () {
4707	    var that = this
4708	    clearTimeout(this.timeout)
4709	    this.hide(function () {
4710	      that.$element.off('.' + that.type).removeData('bs.' + that.type)
4711	      if (that.$tip) {
4712	        that.$tip.detach()
4713	      }
4714	      that.$tip = null
4715	      that.$arrow = null
4716	      that.$viewport = null
4717	      that.$element = null
4718	    })
4719	  }
4720
4721
4722	  // TOOLTIP PLUGIN DEFINITION
4723	  // =========================
4724
4725	  function Plugin(option) {
4726	    return this.each(function () {
4727	      var $this   = $(this)
4728	      var data    = $this.data('bs.tooltip')
4729	      var options = typeof option == 'object' && option
4730
4731	      if (!data && /destroy|hide/.test(option)) return
4732	      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
4733	      if (typeof option == 'string') data[option]()
4734	    })
4735	  }
4736
4737	  var old = $.fn.tooltip
4738
4739	  $.fn.tooltip             = Plugin
4740	  $.fn.tooltip.Constructor = Tooltip
4741
4742
4743	  // TOOLTIP NO CONFLICT
4744	  // ===================
4745
4746	  $.fn.tooltip.noConflict = function () {
4747	    $.fn.tooltip = old
4748	    return this
4749	  }
4750
4751	}(jQuery);
4752
4753
4754/***/ }),
4755
4756/***/ 315:
4757/***/ (function(module, exports) {
4758
4759	/* ========================================================================
4760	 * Bootstrap: popover.js v3.3.7
4761	 * http://getbootstrap.com/javascript/#popovers
4762	 * ========================================================================
4763	 * Copyright 2011-2016 Twitter, Inc.
4764	 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
4765	 * ======================================================================== */
4766
4767
4768	+function ($) {
4769	  'use strict';
4770
4771	  // POPOVER PUBLIC CLASS DEFINITION
4772	  // ===============================
4773
4774	  var Popover = function (element, options) {
4775	    this.init('popover', element, options)
4776	  }
4777
4778	  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
4779
4780	  Popover.VERSION  = '3.3.7'
4781
4782	  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
4783	    placement: 'right',
4784	    trigger: 'click',
4785	    content: '',
4786	    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
4787	  })
4788
4789
4790	  // NOTE: POPOVER EXTENDS tooltip.js
4791	  // ================================
4792
4793	  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
4794
4795	  Popover.prototype.constructor = Popover
4796
4797	  Popover.prototype.getDefaults = function () {
4798	    return Popover.DEFAULTS
4799	  }
4800
4801	  Popover.prototype.setContent = function () {
4802	    var $tip    = this.tip()
4803	    var title   = this.getTitle()
4804	    var content = this.getContent()
4805
4806	    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
4807	    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
4808	      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
4809	    ](content)
4810
4811	    $tip.removeClass('fade top bottom left right in')
4812
4813	    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
4814	    // this manually by checking the contents.
4815	    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
4816	  }
4817
4818	  Popover.prototype.hasContent = function () {
4819	    return this.getTitle() || this.getContent()
4820	  }
4821
4822	  Popover.prototype.getContent = function () {
4823	    var $e = this.$element
4824	    var o  = this.options
4825
4826	    return $e.attr('data-content')
4827	      || (typeof o.content == 'function' ?
4828	            o.content.call($e[0]) :
4829	            o.content)
4830	  }
4831
4832	  Popover.prototype.arrow = function () {
4833	    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
4834	  }
4835
4836
4837	  // POPOVER PLUGIN DEFINITION
4838	  // =========================
4839
4840	  function Plugin(option) {
4841	    return this.each(function () {
4842	      var $this   = $(this)
4843	      var data    = $this.data('bs.popover')
4844	      var options = typeof option == 'object' && option
4845
4846	      if (!data && /destroy|hide/.test(option)) return
4847	      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
4848	      if (typeof option == 'string') data[option]()
4849	    })
4850	  }
4851
4852	  var old = $.fn.popover
4853
4854	  $.fn.popover             = Plugin
4855	  $.fn.popover.Constructor = Popover
4856
4857
4858	  // POPOVER NO CONFLICT
4859	  // ===================
4860
4861	  $.fn.popover.noConflict = function () {
4862	    $.fn.popover = old
4863	    return this
4864	  }
4865
4866	}(jQuery);
4867
4868
4869/***/ }),
4870
4871/***/ 316:
4872/***/ (function(module, exports, __webpack_require__) {
4873
4874	var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
4875	 * jQuery Form Plugin
4876	 * version: 3.50.0-2014.02.05
4877	 * Requires jQuery v1.5 or later
4878	 * Copyright (c) 2013 M. Alsup
4879	 * Examples and documentation at: http://malsup.com/jquery/form/
4880	 * Project repository: https://github.com/malsup/form
4881	 * Dual licensed under the MIT and GPL licenses.
4882	 * https://github.com/malsup/form#copyright-and-license
4883	 */
4884	/*global ActiveXObject */
4885
4886	// AMD support
4887	(function (factory) {
4888	    "use strict";
4889	    if (true) {
4890	        // using AMD; register as anon module
4891	        !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(270)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
4892	    } else {
4893	        // no AMD; invoke directly
4894	        factory( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto );
4895	    }
4896	}
4897
4898	(function($) {
4899	"use strict";
4900
4901	/*
4902	    Usage Note:
4903	    -----------
4904	    Do not use both ajaxSubmit and ajaxForm on the same form.  These
4905	    functions are mutually exclusive.  Use ajaxSubmit if you want
4906	    to bind your own submit handler to the form.  For example,
4907
4908	    $(document).ready(function() {
4909	        $('#myForm').on('submit', function(e) {
4910	            e.preventDefault(); // <-- important
4911	            $(this).ajaxSubmit({
4912	                target: '#output'
4913	            });
4914	        });
4915	    });
4916
4917	    Use ajaxForm when you want the plugin to manage all the event binding
4918	    for you.  For example,
4919
4920	    $(document).ready(function() {
4921	        $('#myForm').ajaxForm({
4922	            target: '#output'
4923	        });
4924	    });
4925
4926	    You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
4927	    form does not have to exist when you invoke ajaxForm:
4928
4929	    $('#myForm').ajaxForm({
4930	        delegation: true,
4931	        target: '#output'
4932	    });
4933
4934	    When using ajaxForm, the ajaxSubmit function will be invoked for you
4935	    at the appropriate time.
4936	*/
4937
4938	/**
4939	 * Feature detection
4940	 */
4941	var feature = {};
4942	feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
4943	feature.formdata = window.FormData !== undefined;
4944
4945	var hasProp = !!$.fn.prop;
4946
4947	// attr2 uses prop when it can but checks the return type for
4948	// an expected string.  this accounts for the case where a form
4949	// contains inputs with names like "action" or "method"; in those
4950	// cases "prop" returns the element
4951	$.fn.attr2 = function() {
4952	    if ( ! hasProp ) {
4953	        return this.attr.apply(this, arguments);
4954	    }
4955	    var val = this.prop.apply(this, arguments);
4956	    if ( ( val && val.jquery ) || typeof val === 'string' ) {
4957	        return val;
4958	    }
4959	    return this.attr.apply(this, arguments);
4960	};
4961
4962	/**
4963	 * ajaxSubmit() provides a mechanism for immediately submitting
4964	 * an HTML form using AJAX.
4965	 */
4966	$.fn.ajaxSubmit = function(options) {
4967	    /*jshint scripturl:true */
4968
4969	    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
4970	    if (!this.length) {
4971	        log('ajaxSubmit: skipping submit process - no element selected');
4972	        return this;
4973	    }
4974
4975	    var method, action, url, $form = this;
4976
4977	    if (typeof options == 'function') {
4978	        options = { success: options };
4979	    }
4980	    else if ( options === undefined ) {
4981	        options = {};
4982	    }
4983
4984	    method = options.type || this.attr2('method');
4985	    action = options.url  || this.attr2('action');
4986
4987	    url = (typeof action === 'string') ? $.trim(action) : '';
4988	    url = url || window.location.href || '';
4989	    if (url) {
4990	        // clean url (don't include hash vaue)
4991	        url = (url.match(/^([^#]+)/)||[])[1];
4992	    }
4993
4994	    options = $.extend(true, {
4995	        url:  url,
4996	        success: $.ajaxSettings.success,
4997	        type: method || $.ajaxSettings.type,
4998	        iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
4999	    }, options);
5000
5001	    // hook for manipulating the form data before it is extracted;
5002	    // convenient for use with rich editors like tinyMCE or FCKEditor
5003	    var veto = {};
5004	    this.trigger('form-pre-serialize', [this, options, veto]);
5005	    if (veto.veto) {
5006	        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
5007	        return this;
5008	    }
5009
5010	    // provide opportunity to alter form data before it is serialized
5011	    if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
5012	        log('ajaxSubmit: submit aborted via beforeSerialize callback');
5013	        return this;
5014	    }
5015
5016	    var traditional = options.traditional;
5017	    if ( traditional === undefined ) {
5018	        traditional = $.ajaxSettings.traditional;
5019	    }
5020
5021	    var elements = [];
5022	    var qx, a = this.formToArray(options.semantic, elements);
5023	    if (options.data) {
5024	        options.extraData = options.data;
5025	        qx = $.param(options.data, traditional);
5026	    }
5027
5028	    // give pre-submit callback an opportunity to abort the submit
5029	    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
5030	        log('ajaxSubmit: submit aborted via beforeSubmit callback');
5031	        return this;
5032	    }
5033
5034	    // fire vetoable 'validate' event
5035	    this.trigger('form-submit-validate', [a, this, options, veto]);
5036	    if (veto.veto) {
5037	        log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
5038	        return this;
5039	    }
5040
5041	    var q = $.param(a, traditional);
5042	    if (qx) {
5043	        q = ( q ? (q + '&' + qx) : qx );
5044	    }
5045	    if (options.type.toUpperCase() == 'GET') {
5046	        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
5047	        options.data = null;  // data is null for 'get'
5048	    }
5049	    else {
5050	        options.data = q; // data is the query string for 'post'
5051	    }
5052
5053	    var callbacks = [];
5054	    if (options.resetForm) {
5055	        callbacks.push(function() { $form.resetForm(); });
5056	    }
5057	    if (options.clearForm) {
5058	        callbacks.push(function() { $form.clearForm(options.includeHidden); });
5059	    }
5060
5061	    // perform a load on the target only if dataType is not provided
5062	    if (!options.dataType && options.target) {
5063	        var oldSuccess = options.success || function(){};
5064	        callbacks.push(function(data) {
5065	            var fn = options.replaceTarget ? 'replaceWith' : 'html';
5066	            $(options.target)[fn](data).each(oldSuccess, arguments);
5067	        });
5068	    }
5069	    else if (options.success) {
5070	        callbacks.push(options.success);
5071	    }
5072
5073	    options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
5074	        var context = options.context || this ;    // jQuery 1.4+ supports scope context
5075	        for (var i=0, max=callbacks.length; i < max; i++) {
5076	            callbacks[i].apply(context, [data, status, xhr || $form, $form]);
5077	        }
5078	    };
5079
5080	    if (options.error) {
5081	        var oldError = options.error;
5082	        options.error = function(xhr, status, error) {
5083	            var context = options.context || this;
5084	            oldError.apply(context, [xhr, status, error, $form]);
5085	        };
5086	    }
5087
5088	     if (options.complete) {
5089	        var oldComplete = options.complete;
5090	        options.complete = function(xhr, status) {
5091	            var context = options.context || this;
5092	            oldComplete.apply(context, [xhr, status, $form]);
5093	        };
5094	    }
5095
5096	    // are there files to upload?
5097
5098	    // [value] (issue #113), also see comment:
5099	    // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
5100	    var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; });
5101
5102	    var hasFileInputs = fileInputs.length > 0;
5103	    var mp = 'multipart/form-data';
5104	    var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
5105
5106	    var fileAPI = feature.fileapi && feature.formdata;
5107	    log("fileAPI :" + fileAPI);
5108	    var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
5109
5110	    var jqxhr;
5111
5112	    // options.iframe allows user to force iframe mode
5113	    // 06-NOV-09: now defaulting to iframe mode if file input is detected
5114	    if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
5115	        // hack to fix Safari hang (thanks to Tim Molendijk for this)
5116	        // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
5117	        if (options.closeKeepAlive) {
5118	            $.get(options.closeKeepAlive, function() {
5119	                jqxhr = fileUploadIframe(a);
5120	            });
5121	        }
5122	        else {
5123	            jqxhr = fileUploadIframe(a);
5124	        }
5125	    }
5126	    else if ((hasFileInputs || multipart) && fileAPI) {
5127	        jqxhr = fileUploadXhr(a);
5128	    }
5129	    else {
5130	        jqxhr = $.ajax(options);
5131	    }
5132
5133	    $form.removeData('jqxhr').data('jqxhr', jqxhr);
5134
5135	    // clear element array
5136	    for (var k=0; k < elements.length; k++) {
5137	        elements[k] = null;
5138	    }
5139
5140	    // fire 'notify' event
5141	    this.trigger('form-submit-notify', [this, options]);
5142	    return this;
5143
5144	    // utility fn for deep serialization
5145	    function deepSerialize(extraData){
5146	        var serialized = $.param(extraData, options.traditional).split('&');
5147	        var len = serialized.length;
5148	        var result = [];
5149	        var i, part;
5150	        for (i=0; i < len; i++) {
5151	            // #252; undo param space replacement
5152	            serialized[i] = serialized[i].replace(/\+/g,' ');
5153	            part = serialized[i].split('=');
5154	            // #278; use array instead of object storage, favoring array serializations
5155	            result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
5156	        }
5157	        return result;
5158	    }
5159
5160	     // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
5161	    function fileUploadXhr(a) {
5162	        var formdata = new FormData();
5163
5164	        for (var i=0; i < a.length; i++) {
5165	            formdata.append(a[i].name, a[i].value);
5166	        }
5167
5168	        if (options.extraData) {
5169	            var serializedData = deepSerialize(options.extraData);
5170	            for (i=0; i < serializedData.length; i++) {
5171	                if (serializedData[i]) {
5172	                    formdata.append(serializedData[i][0], serializedData[i][1]);
5173	                }
5174	            }
5175	        }
5176
5177	        options.data = null;
5178
5179	        var s = $.extend(true, {}, $.ajaxSettings, options, {
5180	            contentType: false,
5181	            processData: false,
5182	            cache: false,
5183	            type: method || 'POST'
5184	        });
5185
5186	        if (options.uploadProgress) {
5187	            // workaround because jqXHR does not expose upload property
5188	            s.xhr = function() {
5189	                var xhr = $.ajaxSettings.xhr();
5190	                if (xhr.upload) {
5191	                    xhr.upload.addEventListener('progress', function(event) {
5192	                        var percent = 0;
5193	                        var position = event.loaded || event.position; /*event.position is deprecated*/
5194	                        var total = event.total;
5195	                        if (event.lengthComputable) {
5196	                            percent = Math.ceil(position / total * 100);
5197	                        }
5198	                        options.uploadProgress(event, position, total, percent);
5199	                    }, false);
5200	                }
5201	                return xhr;
5202	            };
5203	        }
5204
5205	        s.data = null;
5206	        var beforeSend = s.beforeSend;
5207	        s.beforeSend = function(xhr, o) {
5208	            //Send FormData() provided by user
5209	            if (options.formData) {
5210	                o.data = options.formData;
5211	            }
5212	            else {
5213	                o.data = formdata;
5214	            }
5215	            if(beforeSend) {
5216	                beforeSend.call(this, xhr, o);
5217	            }
5218	        };
5219	        return $.ajax(s);
5220	    }
5221
5222	    // private function for handling file uploads (hat tip to YAHOO!)
5223	    function fileUploadIframe(a) {
5224	        var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
5225	        var deferred = $.Deferred();
5226
5227	        // #341
5228	        deferred.abort = function(status) {
5229	            xhr.abort(status);
5230	        };
5231
5232	        if (a) {
5233	            // ensure that every serialized input is still enabled
5234	            for (i=0; i < elements.length; i++) {
5235	                el = $(elements[i]);
5236	                if ( hasProp ) {
5237	                    el.prop('disabled', false);
5238	                }
5239	                else {
5240	                    el.removeAttr('disabled');
5241	                }
5242	            }
5243	        }
5244
5245	        s = $.extend(true, {}, $.ajaxSettings, options);
5246	        s.context = s.context || s;
5247	        id = 'jqFormIO' + (new Date().getTime());
5248	        if (s.iframeTarget) {
5249	            $io = $(s.iframeTarget);
5250	            n = $io.attr2('name');
5251	            if (!n) {
5252	                $io.attr2('name', id);
5253	            }
5254	            else {
5255	                id = n;
5256	            }
5257	        }
5258	        else {
5259	            $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
5260	            $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
5261	        }
5262	        io = $io[0];
5263
5264
5265	        xhr = { // mock object
5266	            aborted: 0,
5267	            responseText: null,
5268	            responseXML: null,
5269	            status: 0,
5270	            statusText: 'n/a',
5271	            getAllResponseHeaders: function() {},
5272	            getResponseHeader: function() {},
5273	            setRequestHeader: function() {},
5274	            abort: function(status) {
5275	                var e = (status === 'timeout' ? 'timeout' : 'aborted');
5276	                log('aborting upload... ' + e);
5277	                this.aborted = 1;
5278
5279	                try { // #214, #257
5280	                    if (io.contentWindow.document.execCommand) {
5281	                        io.contentWindow.document.execCommand('Stop');
5282	                    }
5283	                }
5284	                catch(ignore) {}
5285
5286	                $io.attr('src', s.iframeSrc); // abort op in progress
5287	                xhr.error = e;
5288	                if (s.error) {
5289	                    s.error.call(s.context, xhr, e, status);
5290	                }
5291	                if (g) {
5292	                    $.event.trigger("ajaxError", [xhr, s, e]);
5293	                }
5294	                if (s.complete) {
5295	                    s.complete.call(s.context, xhr, e);
5296	                }
5297	            }
5298	        };
5299
5300	        g = s.global;
5301	        // trigger ajax global events so that activity/block indicators work like normal
5302	        if (g && 0 === $.active++) {
5303	            $.event.trigger("ajaxStart");
5304	        }
5305	        if (g) {
5306	            $.event.trigger("ajaxSend", [xhr, s]);
5307	        }
5308
5309	        if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
5310	            if (s.global) {
5311	                $.active--;
5312	            }
5313	            deferred.reject();
5314	            return deferred;
5315	        }
5316	        if (xhr.aborted) {
5317	            deferred.reject();
5318	            return deferred;
5319	        }
5320
5321	        // add submitting element to data if we know it
5322	        sub = form.clk;
5323	        if (sub) {
5324	            n = sub.name;
5325	            if (n && !sub.disabled) {
5326	                s.extraData = s.extraData || {};
5327	                s.extraData[n] = sub.value;
5328	                if (sub.type == "image") {
5329	                    s.extraData[n+'.x'] = form.clk_x;
5330	                    s.extraData[n+'.y'] = form.clk_y;
5331	                }
5332	            }
5333	        }
5334
5335	        var CLIENT_TIMEOUT_ABORT = 1;
5336	        var SERVER_ABORT = 2;
5337
5338	        function getDoc(frame) {
5339	            /* it looks like contentWindow or contentDocument do not
5340	             * carry the protocol property in ie8, when running under ssl
5341	             * frame.document is the only valid response document, since
5342	             * the protocol is know but not on the other two objects. strange?
5343	             * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy
5344	             */
5345
5346	            var doc = null;
5347
5348	            // IE8 cascading access check
5349	            try {
5350	                if (frame.contentWindow) {
5351	                    doc = frame.contentWindow.document;
5352	                }
5353	            } catch(err) {
5354	                // IE8 access denied under ssl & missing protocol
5355	                log('cannot get iframe.contentWindow document: ' + err);
5356	            }
5357
5358	            if (doc) { // successful getting content
5359	                return doc;
5360	            }
5361
5362	            try { // simply checking may throw in ie8 under ssl or mismatched protocol
5363	                doc = frame.contentDocument ? frame.contentDocument : frame.document;
5364	            } catch(err) {
5365	                // last attempt
5366	                log('cannot get iframe.contentDocument: ' + err);
5367	                doc = frame.document;
5368	            }
5369	            return doc;
5370	        }
5371
5372	        // Rails CSRF hack (thanks to Yvan Barthelemy)
5373	        var csrf_token = $('meta[name=csrf-token]').attr('content');
5374	        var csrf_param = $('meta[name=csrf-param]').attr('content');
5375	        if (csrf_param && csrf_token) {
5376	            s.extraData = s.extraData || {};
5377	            s.extraData[csrf_param] = csrf_token;
5378	        }
5379
5380	        // take a breath so that pending repaints get some cpu time before the upload starts
5381	        function doSubmit() {
5382	            // make sure form attrs are set
5383	            var t = $form.attr2('target'),
5384	                a = $form.attr2('action'),
5385	                mp = 'multipart/form-data',
5386	                et = $form.attr('enctype') || $form.attr('encoding') || mp;
5387
5388	            // update form attrs in IE friendly way
5389	            form.setAttribute('target',id);
5390	            if (!method || /post/i.test(method) ) {
5391	                form.setAttribute('method', 'POST');
5392	            }
5393	            if (a != s.url) {
5394	                form.setAttribute('action', s.url);
5395	            }
5396
5397	            // ie borks in some cases when setting encoding
5398	            if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
5399	                $form.attr({
5400	                    encoding: 'multipart/form-data',
5401	                    enctype:  'multipart/form-data'
5402	                });
5403	            }
5404
5405	            // support timout
5406	            if (s.timeout) {
5407	                timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
5408	            }
5409
5410	            // look for server aborts
5411	            function checkState() {
5412	                try {
5413	                    var state = getDoc(io).readyState;
5414	                    log('state = ' + state);
5415	                    if (state && state.toLowerCase() == 'uninitialized') {
5416	                        setTimeout(checkState,50);
5417	                    }
5418	                }
5419	                catch(e) {
5420	                    log('Server abort: ' , e, ' (', e.name, ')');
5421	                    cb(SERVER_ABORT);
5422	                    if (timeoutHandle) {
5423	                        clearTimeout(timeoutHandle);
5424	                    }
5425	                    timeoutHandle = undefined;
5426	                }
5427	            }
5428
5429	            // add "extra" data to form if provided in options
5430	            var extraInputs = [];
5431	            try {
5432	                if (s.extraData) {
5433	                    for (var n in s.extraData) {
5434	                        if (s.extraData.hasOwnProperty(n)) {
5435	                           // if using the $.param format that allows for multiple values with the same name
5436	                           if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
5437	                               extraInputs.push(
5438	                               $('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value)
5439	                                   .appendTo(form)[0]);
5440	                           } else {
5441	                               extraInputs.push(
5442	                               $('<input type="hidden" name="'+n+'">').val(s.extraData[n])
5443	                                   .appendTo(form)[0]);
5444	                           }
5445	                        }
5446	                    }
5447	                }
5448
5449	                if (!s.iframeTarget) {
5450	                    // add iframe to doc and submit the form
5451	                    $io.appendTo('body');
5452	                }
5453	                if (io.attachEvent) {
5454	                    io.attachEvent('onload', cb);
5455	                }
5456	                else {
5457	                    io.addEventListener('load', cb, false);
5458	                }
5459	                setTimeout(checkState,15);
5460
5461	                try {
5462	                    form.submit();
5463	                } catch(err) {
5464	                    // just in case form has element with name/id of 'submit'
5465	                    var submitFn = document.createElement('form').submit;
5466	                    submitFn.apply(form);
5467	                }
5468	            }
5469	            finally {
5470	                // reset attrs and remove "extra" input elements
5471	                form.setAttribute('action',a);
5472	                form.setAttribute('enctype', et); // #380
5473	                if(t) {
5474	                    form.setAttribute('target', t);
5475	                } else {
5476	                    $form.removeAttr('target');
5477	                }
5478	                $(extraInputs).remove();
5479	            }
5480	        }
5481
5482	        if (s.forceSync) {
5483	            doSubmit();
5484	        }
5485	        else {
5486	            setTimeout(doSubmit, 10); // this lets dom updates render
5487	        }
5488
5489	        var data, doc, domCheckCount = 50, callbackProcessed;
5490
5491	        function cb(e) {
5492	            if (xhr.aborted || callbackProcessed) {
5493	                return;
5494	            }
5495
5496	            doc = getDoc(io);
5497	            if(!doc) {
5498	                log('cannot access response document');
5499	                e = SERVER_ABORT;
5500	            }
5501	            if (e === CLIENT_TIMEOUT_ABORT && xhr) {
5502	                xhr.abort('timeout');
5503	                deferred.reject(xhr, 'timeout');
5504	                return;
5505	            }
5506	            else if (e == SERVER_ABORT && xhr) {
5507	                xhr.abort('server abort');
5508	                deferred.reject(xhr, 'error', 'server abort');
5509	                return;
5510	            }
5511
5512	            if (!doc || doc.location.href == s.iframeSrc) {
5513	                // response not received yet
5514	                if (!timedOut) {
5515	                    return;
5516	                }
5517	            }
5518	            if (io.detachEvent) {
5519	                io.detachEvent('onload', cb);
5520	            }
5521	            else {
5522	                io.removeEventListener('load', cb, false);
5523	            }
5524
5525	            var status = 'success', errMsg;
5526	            try {
5527	                if (timedOut) {
5528	                    throw 'timeout';
5529	                }
5530
5531	                var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
5532	                log('isXml='+isXml);
5533	                if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
5534	                    if (--domCheckCount) {
5535	                        // in some browsers (Opera) the iframe DOM is not always traversable when
5536	                        // the onload callback fires, so we loop a bit to accommodate
5537	                        log('requeing onLoad callback, DOM not available');
5538	                        setTimeout(cb, 250);
5539	                        return;
5540	                    }
5541	                    // let this fall through because server response could be an empty document
5542	                    //log('Could not access iframe DOM after mutiple tries.');
5543	                    //throw 'DOMException: not available';
5544	                }
5545
5546	                //log('response detected');
5547	                var docRoot = doc.body ? doc.body : doc.documentElement;
5548	                xhr.responseText = docRoot ? docRoot.innerHTML : null;
5549	                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
5550	                if (isXml) {
5551	                    s.dataType = 'xml';
5552	                }
5553	                xhr.getResponseHeader = function(header){
5554	                    var headers = {'content-type': s.dataType};
5555	                    return headers[header.toLowerCase()];
5556	                };
5557	                // support for XHR 'status' & 'statusText' emulation :
5558	                if (docRoot) {
5559	                    xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
5560	                    xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
5561	                }
5562
5563	                var dt = (s.dataType || '').toLowerCase();
5564	                var scr = /(json|script|text)/.test(dt);
5565	                if (scr || s.textarea) {
5566	                    // see if user embedded response in textarea
5567	                    var ta = doc.getElementsByTagName('textarea')[0];
5568	                    if (ta) {
5569	                        xhr.responseText = ta.value;
5570	                        // support for XHR 'status' & 'statusText' emulation :
5571	                        xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
5572	                        xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
5573	                    }
5574	                    else if (scr) {
5575	                        // account for browsers injecting pre around json response
5576	                        var pre = doc.getElementsByTagName('pre')[0];
5577	                        var b = doc.getElementsByTagName('body')[0];
5578	                        if (pre) {
5579	                            xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
5580	                        }
5581	                        else if (b) {
5582	                            xhr.responseText = b.textContent ? b.textContent : b.innerText;
5583	                        }
5584	                    }
5585	                }
5586	                else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
5587	                    xhr.responseXML = toXml(xhr.responseText);
5588	                }
5589
5590	                try {
5591	                    data = httpData(xhr, dt, s);
5592	                }
5593	                catch (err) {
5594	                    status = 'parsererror';
5595	                    xhr.error = errMsg = (err || status);
5596	                }
5597	            }
5598	            catch (err) {
5599	                log('error caught: ',err);
5600	                status = 'error';
5601	                xhr.error = errMsg = (err || status);
5602	            }
5603
5604	            if (xhr.aborted) {
5605	                log('upload aborted');
5606	                status = null;
5607	            }
5608
5609	            if (xhr.status) { // we've set xhr.status
5610	                status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
5611	            }
5612
5613	            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
5614	            if (status === 'success') {
5615	                if (s.success) {
5616	                    s.success.call(s.context, data, 'success', xhr);
5617	                }
5618	                deferred.resolve(xhr.responseText, 'success', xhr);
5619	                if (g) {
5620	                    $.event.trigger("ajaxSuccess", [xhr, s]);
5621	                }
5622	            }
5623	            else if (status) {
5624	                if (errMsg === undefined) {
5625	                    errMsg = xhr.statusText;
5626	                }
5627	                if (s.error) {
5628	                    s.error.call(s.context, xhr, status, errMsg);
5629	                }
5630	                deferred.reject(xhr, 'error', errMsg);
5631	                if (g) {
5632	                    $.event.trigger("ajaxError", [xhr, s, errMsg]);
5633	                }
5634	            }
5635
5636	            if (g) {
5637	                $.event.trigger("ajaxComplete", [xhr, s]);
5638	            }
5639
5640	            if (g && ! --$.active) {
5641	                $.event.trigger("ajaxStop");
5642	            }
5643
5644	            if (s.complete) {
5645	                s.complete.call(s.context, xhr, status);
5646	            }
5647
5648	            callbackProcessed = true;
5649	            if (s.timeout) {
5650	                clearTimeout(timeoutHandle);
5651	            }
5652
5653	            // clean up
5654	            setTimeout(function() {
5655	                if (!s.iframeTarget) {
5656	                    $io.remove();
5657	                }
5658	                else { //adding else to clean up existing iframe response.
5659	                    $io.attr('src', s.iframeSrc);
5660	                }
5661	                xhr.responseXML = null;
5662	            }, 100);
5663	        }
5664
5665	        var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
5666	            if (window.ActiveXObject) {
5667	                doc = new ActiveXObject('Microsoft.XMLDOM');
5668	                doc.async = 'false';
5669	                doc.loadXML(s);
5670	            }
5671	            else {
5672	                doc = (new DOMParser()).parseFromString(s, 'text/xml');
5673	            }
5674	            return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
5675	        };
5676	        var parseJSON = $.parseJSON || function(s) {
5677	            /*jslint evil:true */
5678	            return window['eval']('(' + s + ')');
5679	        };
5680
5681	        var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
5682
5683	            var ct = xhr.getResponseHeader('content-type') || '',
5684	                xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
5685	                data = xml ? xhr.responseXML : xhr.responseText;
5686
5687	            if (xml && data.documentElement.nodeName === 'parsererror') {
5688	                if ($.error) {
5689	                    $.error('parsererror');
5690	                }
5691	            }
5692	            if (s && s.dataFilter) {
5693	                data = s.dataFilter(data, type);
5694	            }
5695	            if (typeof data === 'string') {
5696	                if (type === 'json' || !type && ct.indexOf('json') >= 0) {
5697	                    data = parseJSON(data);
5698	                } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
5699	                    $.globalEval(data);
5700	                }
5701	            }
5702	            return data;
5703	        };
5704
5705	        return deferred;
5706	    }
5707	};
5708
5709	/**
5710	 * ajaxForm() provides a mechanism for fully automating form submission.
5711	 *
5712	 * The advantages of using this method instead of ajaxSubmit() are:
5713	 *
5714	 * 1: This method will include coordinates for <input type="image" /> elements (if the element
5715	 *    is used to submit the form).
5716	 * 2. This method will include the submit element's name/value data (for the element that was
5717	 *    used to submit the form).
5718	 * 3. This method binds the submit() method to the form for you.
5719	 *
5720	 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
5721	 * passes the options argument along after properly binding events for submit elements and
5722	 * the form itself.
5723	 */
5724	$.fn.ajaxForm = function(options) {
5725	    options = options || {};
5726	    options.delegation = options.delegation && $.isFunction($.fn.on);
5727
5728	    // in jQuery 1.3+ we can fix mistakes with the ready state
5729	    if (!options.delegation && this.length === 0) {
5730	        var o = { s: this.selector, c: this.context };
5731	        if (!$.isReady && o.s) {
5732	            log('DOM not ready, queuing ajaxForm');
5733	            $(function() {
5734	                $(o.s,o.c).ajaxForm(options);
5735	            });
5736	            return this;
5737	        }
5738	        // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
5739	        log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
5740	        return this;
5741	    }
5742
5743	    if ( options.delegation ) {
5744	        $(document)
5745	            .off('submit.form-plugin', this.selector, doAjaxSubmit)
5746	            .off('click.form-plugin', this.selector, captureSubmittingElement)
5747	            .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
5748	            .on('click.form-plugin', this.selector, options, captureSubmittingElement);
5749	        return this;
5750	    }
5751
5752	    return this.ajaxFormUnbind()
5753	        .bind('submit.form-plugin', options, doAjaxSubmit)
5754	        .bind('click.form-plugin', options, captureSubmittingElement);
5755	};
5756
5757	// private event handlers
5758	function doAjaxSubmit(e) {
5759	    /*jshint validthis:true */
5760	    var options = e.data;
5761	    if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
5762	        e.preventDefault();
5763	        $(e.target).ajaxSubmit(options); // #365
5764	    }
5765	}
5766
5767	function captureSubmittingElement(e) {
5768	    /*jshint validthis:true */
5769	    var target = e.target;
5770	    var $el = $(target);
5771	    if (!($el.is("[type=submit],[type=image]"))) {
5772	        // is this a child element of the submit el?  (ex: a span within a button)
5773	        var t = $el.closest('[type=submit]');
5774	        if (t.length === 0) {
5775	            return;
5776	        }
5777	        target = t[0];
5778	    }
5779	    var form = this;
5780	    form.clk = target;
5781	    if (target.type == 'image') {
5782	        if (e.offsetX !== undefined) {
5783	            form.clk_x = e.offsetX;
5784	            form.clk_y = e.offsetY;
5785	        } else if (typeof $.fn.offset == 'function') {
5786	            var offset = $el.offset();
5787	            form.clk_x = e.pageX - offset.left;
5788	            form.clk_y = e.pageY - offset.top;
5789	        } else {
5790	            form.clk_x = e.pageX - target.offsetLeft;
5791	            form.clk_y = e.pageY - target.offsetTop;
5792	        }
5793	    }
5794	    // clear form vars
5795	    setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
5796	}
5797
5798
5799	// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
5800	$.fn.ajaxFormUnbind = function() {
5801	    return this.unbind('submit.form-plugin click.form-plugin');
5802	};
5803
5804	/**
5805	 * formToArray() gathers form element data into an array of objects that can
5806	 * be passed to any of the following ajax functions: $.get, $.post, or load.
5807	 * Each object in the array has both a 'name' and 'value' property.  An example of
5808	 * an array for a simple login form might be:
5809	 *
5810	 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
5811	 *
5812	 * It is this array that is passed to pre-submit callback functions provided to the
5813	 * ajaxSubmit() and ajaxForm() methods.
5814	 */
5815	$.fn.formToArray = function(semantic, elements) {
5816	    var a = [];
5817	    if (this.length === 0) {
5818	        return a;
5819	    }
5820
5821	    var form = this[0];
5822	    var formId = this.attr('id');
5823	    var els = semantic ? form.getElementsByTagName('*') : form.elements;
5824	    var els2;
5825
5826	    if (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390
5827	        els = $(els).get();  // convert to standard array
5828	    }
5829
5830	    // #386; account for inputs outside the form which use the 'form' attribute
5831	    if ( formId ) {
5832	        els2 = $(':input[form=' + formId + ']').get();
5833	        if ( els2.length ) {
5834	            els = (els || []).concat(els2);
5835	        }
5836	    }
5837
5838	    if (!els || !els.length) {
5839	        return a;
5840	    }
5841
5842	    var i,j,n,v,el,max,jmax;
5843	    for(i=0, max=els.length; i < max; i++) {
5844	        el = els[i];
5845	        n = el.name;
5846	        if (!n || el.disabled) {
5847	            continue;
5848	        }
5849
5850	        if (semantic && form.clk && el.type == "image") {
5851	            // handle image inputs on the fly when semantic == true
5852	            if(form.clk == el) {
5853	                a.push({name: n, value: $(el).val(), type: el.type });
5854	                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
5855	            }
5856	            continue;
5857	        }
5858
5859	        v = $.fieldValue(el, true);
5860	        if (v && v.constructor == Array) {
5861	            if (elements) {
5862	                elements.push(el);
5863	            }
5864	            for(j=0, jmax=v.length; j < jmax; j++) {
5865	                a.push({name: n, value: v[j]});
5866	            }
5867	        }
5868	        else if (feature.fileapi && el.type == 'file') {
5869	            if (elements) {
5870	                elements.push(el);
5871	            }
5872	            var files = el.files;
5873	            if (files.length) {
5874	                for (j=0; j < files.length; j++) {
5875	                    a.push({name: n, value: files[j], type: el.type});
5876	                }
5877	            }
5878	            else {
5879	                // #180
5880	                a.push({ name: n, value: '', type: el.type });
5881	            }
5882	        }
5883	        else if (v !== null && typeof v != 'undefined') {
5884	            if (elements) {
5885	                elements.push(el);
5886	            }
5887	            a.push({name: n, value: v, type: el.type, required: el.required});
5888	        }
5889	    }
5890
5891	    if (!semantic && form.clk) {
5892	        // input type=='image' are not found in elements array! handle it here
5893	        var $input = $(form.clk), input = $input[0];
5894	        n = input.name;
5895	        if (n && !input.disabled && input.type == 'image') {
5896	            a.push({name: n, value: $input.val()});
5897	            a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
5898	        }
5899	    }
5900	    return a;
5901	};
5902
5903	/**
5904	 * Serializes form data into a 'submittable' string. This method will return a string
5905	 * in the format: name1=value1&amp;name2=value2
5906	 */
5907	$.fn.formSerialize = function(semantic) {
5908	    //hand off to jQuery.param for proper encoding
5909	    return $.param(this.formToArray(semantic));
5910	};
5911
5912	/**
5913	 * Serializes all field elements in the jQuery object into a query string.
5914	 * This method will return a string in the format: name1=value1&amp;name2=value2
5915	 */
5916	$.fn.fieldSerialize = function(successful) {
5917	    var a = [];
5918	    this.each(function() {
5919	        var n = this.name;
5920	        if (!n) {
5921	            return;
5922	        }
5923	        var v = $.fieldValue(this, successful);
5924	        if (v && v.constructor == Array) {
5925	            for (var i=0,max=v.length; i < max; i++) {
5926	                a.push({name: n, value: v[i]});
5927	            }
5928	        }
5929	        else if (v !== null && typeof v != 'undefined') {
5930	            a.push({name: this.name, value: v});
5931	        }
5932	    });
5933	    //hand off to jQuery.param for proper encoding
5934	    return $.param(a);
5935	};
5936
5937	/**
5938	 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
5939	 *
5940	 *  <form><fieldset>
5941	 *      <input name="A" type="text" />
5942	 *      <input name="A" type="text" />
5943	 *      <input name="B" type="checkbox" value="B1" />
5944	 *      <input name="B" type="checkbox" value="B2"/>
5945	 *      <input name="C" type="radio" value="C1" />
5946	 *      <input name="C" type="radio" value="C2" />
5947	 *  </fieldset></form>
5948	 *
5949	 *  var v = $('input[type=text]').fieldValue();
5950	 *  // if no values are entered into the text inputs
5951	 *  v == ['','']
5952	 *  // if values entered into the text inputs are 'foo' and 'bar'
5953	 *  v == ['foo','bar']
5954	 *
5955	 *  var v = $('input[type=checkbox]').fieldValue();
5956	 *  // if neither checkbox is checked
5957	 *  v === undefined
5958	 *  // if both checkboxes are checked
5959	 *  v == ['B1', 'B2']
5960	 *
5961	 *  var v = $('input[type=radio]').fieldValue();
5962	 *  // if neither radio is checked
5963	 *  v === undefined
5964	 *  // if first radio is checked
5965	 *  v == ['C1']
5966	 *
5967	 * The successful argument controls whether or not the field element must be 'successful'
5968	 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-control
5968s).
5969	 * The default value of the successful argument is true.  If this value is false the value(s)
5970	 * for each element is returned.
5971	 *
5972	 * Note: This method *always* returns an array.  If no valid value can be determined the
5973	 *    array will be empty, otherwise it will contain one or more values.
5974	 */
5975	$.fn.fieldValue = function(successful) {
5976	    for (var val=[], i=0, max=this.length; i < max; i++) {
5977	        var el = this[i];
5978	        var v = $.fieldValue(el, successful);
5979	        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
5980	            continue;
5981	        }
5982	        if (v.constructor == Array) {
5983	            $.merge(val, v);
5984	        }
5985	        else {
5986	            val.push(v);
5987	        }
5988	    }
5989	    return val;
5990	};
5991
5992	/**
5993	 * Returns the value of the field element.
5994	 */
5995	$.fieldValue = function(el, successful) {
5996	    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
5997	    if (successful === undefined) {
5998	        successful = true;
5999	    }
6000
6001	    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
6002	        (t == 'checkbox' || t == 'radio') && !el.checked ||
6003	        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
6004	        tag == 'select' && el.selectedIndex == -1)) {
6005	            return null;
6006	    }
6007
6008	    if (tag == 'select') {
6009	        var index = el.selectedIndex;
6010	        if (index < 0) {
6011	            return null;
6012	        }
6013	        var a = [], ops = el.options;
6014	        var one = (t == 'select-one');
6015	        var max = (one ? index+1 : ops.length);
6016	        for(var i=(one ? index : 0); i < max; i++) {
6017	            var op = ops[i];
6018	            if (op.selected) {
6019	                var v = op.value;
6020	                if (!v) { // extra pain for IE...
6021	                    v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value;
6022	                }
6023	                if (one) {
6024	                    return v;
6025	                }
6026	                a.push(v);
6027	            }
6028	        }
6029	        return a;
6030	    }
6031	    return $(el).val();
6032	};
6033
6034	/**
6035	 * Clears the form data.  Takes the following actions on the form's input fields:
6036	 *  - input text fields will have their 'value' property set to the empty string
6037	 *  - select elements will have their 'selectedIndex' property set to -1
6038	 *  - checkbox and radio inputs will have their 'checked' property set to false
6039	 *  - inputs of type submit, button, reset, and hidden will *not* be effected
6040	 *  - button elements will *not* be effected
6041	 */
6042	$.fn.clearForm = function(includeHidden) {
6043	    return this.each(function() {
6044	        $('input,select,textarea', this).clearFields(includeHidden);
6045	    });
6046	};
6047
6048	/**
6049	 * Clears the selected form elements.
6050	 */
6051	$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
6052	    var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
6053	    return this.each(function() {
6054	        var t = this.type, tag = this.tagName.toLowerCase();
6055	        if (re.test(t) || tag == 'textarea') {
6056	            this.value = '';
6057	        }
6058	        else if (t == 'checkbox' || t == 'radio') {
6059	            this.checked = false;
6060	        }
6061	        else if (tag == 'select') {
6062	            this.selectedIndex = -1;
6063	        }
6064			else if (t == "file") {
6065				if (/MSIE/.test(navigator.userAgent)) {
6066					$(this).replaceWith($(this).clone(true));
6067				} else {
6068					$(this).val('');
6069				}
6070			}
6071	        else if (includeHidden) {
6072	            // includeHidden can be the value true, or it can be a selector string
6073	            // indicating a special test; for example:
6074	            //  $('#myForm').clearForm('.special:hidden')
6075	            // the above would clean hidden inputs that have the class of 'special'
6076	            if ( (includeHidden === true && /hidden/.test(t)) ||
6077	                 (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) {
6078	                this.value = '';
6079	            }
6080	        }
6081	    });
6082	};
6083
6084	/**
6085	 * Resets the form data.  Causes all form elements to be reset to their original value.
6086	 */
6087	$.fn.resetForm = function() {
6088	    return this.each(function() {
6089	        // guard against an input with the name of 'reset'
6090	        // note that IE reports the reset function as an 'object'
6091	        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
6092	            this.reset();
6093	        }
6094	    });
6095	};
6096
6097	/**
6098	 * Enables or disables any matching elements.
6099	 */
6100	$.fn.enable = function(b) {
6101	    if (b === undefined) {
6102	        b = true;
6103	    }
6104	    return this.each(function() {
6105	        this.disabled = !b;
6106	    });
6107	};
6108
6109	/**
6110	 * Checks/unchecks any matching checkboxes or radio buttons and
6111	 * selects/deselects and matching option elements.
6112	 */
6113	$.fn.selected = function(select) {
6114	    if (select === undefined) {
6115	        select = true;
6116	    }
6117	    return this.each(function() {
6118	        var t = this.type;
6119	        if (t == 'checkbox' || t == 'radio') {
6120	            this.checked = select;
6121	        }
6122	        else if (this.tagName.toLowerCase() == 'option') {
6123	            var $sel = $(this).parent('select');
6124	            if (select && $sel[0] && $sel[0].type == 'select-one') {
6125	                // deselect all other options
6126	                $sel.find('option').selected(false);
6127	            }
6128	            this.selected = select;
6129	        }
6130	    });
6131	};
6132
6133	// expose debug var
6134	$.fn.ajaxSubmit.debug = false;
6135
6136	// helper fn for console logging
6137	function log() {
6138	    if (!$.fn.ajaxSubmit.debug) {
6139	        return;
6140	    }
6141	    var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
6142	    if (window.console && window.console.log) {
6143	        window.console.log(msg);
6144	    }
6145	    else if (window.opera && window.opera.postError) {
6146	        window.opera.postError(msg);
6147	    }
6148	}
6149
6150	}));
6151
6152
6153/***/ }),
6154
6155/***/ 317:
6156/***/ (function(module, exports) {
6157
6158	;(function($) {
6159	  $.fn.fullformWizard = function (options) {
6160	    var $$this = $(this);
6161
6162	    var wizard = {
6163	      settings: {
6164	        submitHandle: null,
6165	        submitHtml: null,
6166	        startStep: ':first',
6167	        elementHandle: '.wizard__step',
6168	        nextPage: '2',
6169	        debug: false,
6170	        validate: true,
6171	        lastStep: function () {},
6172	        onEdit: function () {},
6173	        onEditCancel: function () {},
6174	        translate: {
6175	          buttonEdit: 'edit',
6176	          buttonCancel: 'cancel',
6177	          buttonSubmit: 'submit',
6178	          buttonNext: 'next',
6179	          serverResponseError: 'server error'
6180	        }
6181	      },
6182	      formElements: 'input, select, textarea',
6183	      currentStep: null,
6184	      savedStep: null,
6185	      activeStep: null,
6186	      nextStep: null,
6187	      prevStep: null,
6188	      elements: null,
6189	      lastStep: false,
6190	      lastStepCompleted: false
6191	    };
6192
6193	    wizard.validationSettings = {
6194	      debug: wizard.settings.debug,
6195	      errorClass: 'error',
6196	      errorElement: 'div',
6197	      highlight: $.validateHighlight,
6198	      unhighlight: $.validateUnhighlight,
6199	      errorPlacement: function (error, element) {
6200	        var elem = {
6201	          height: element.outerHeight(),
6202	          width: element.outerWidth(),
6203	          position: element.position()
6204	        }
6205
6206	        var errorHtml  = '<div class="error-box">';
6207	            errorHtml += '<div class="error-arrow"></div>';
6208	            errorHtml += '</div>';
6209
6210	        var errorBox = $(errorHtml).append(error);
6211
6212	        element.after(errorBox);
6213
6214	        var errorWidth = element.next('.error-box').width();
6215	        var errorBoxCss = {
6216	          'position': 'absolute',
6217	          'top': elem.position.top + elem.height,
6218	          'left': elem.position.left,
6219	        };
6220
6221	        if (errorWidth > elem.width){
6222	          errorBoxCss['left'] = '50%'
6223	          errorBoxCss['margin-left'] = -errorWidth/2;
6224	          element.next('.error-box').find('.error-arrow')
6225	            .css({
6226	              'left': '50%',
6227	              'margin-left': -6,
6228	              'position': 'relative'
6229	            })
6230	        }
6231
6232	        element
6233	          .next('.error-box')
6234	          .css(errorBoxCss)
6235	          .append(error);
6236	      }
6237	    }
6238
6239	    // default submit stuff
6240	    wizard.settings.defaultSubmitHandle = 'button[type="submit"]';
6241	    wizard.settings.defaultSubmitHtml   = '<div class="submit"><button type="submit">'+wizard.settings.translate.buttonNext+'</button></div>'
6242
6243	    // allow overwrite of default settings
6244	    $.extend(wizard.settings, options);
6245
6246	    wizard.show = function (target) {
6247	      if ($(target).is(':visible')) {
6248	        return;
6249	      }
6250
6251	      $(target).slideDown(250, 'linear', function () {
6252	        wizard.scrollTo(target);
6253	      });
6254
6255	      wizard.updateSteps();
6256	    };
6257
6258	    wizard.scrollTo = function (target) {
6259	      // check if targt exists
6260	      if (typeof (target.offset()) !== 'undefined') {
6261	        var endPosition = target.offset().top;
6262	        $('html, body').animate({
6263	          scrollTop: endPosition
6264	        }, 150);
6265	      }
6266	    };
6267
6268	    // updates currentStep and nextStep
6269	    wizard.updateSteps = function () {
6270	      if (wizard.lastStep) {
6271	        return;
6272	      }
6273	      wizard.completeStep(wizard.currentStep);
6274	      wizard.currentStep = wizard.currentStep.next(wizard.settings.elementHandle);
6275	      wizard.nextStep = wizard.currentStep.next(wizard.settings.elementHandle);
6276	      if (wizard.nextStep.length <= 0) {
6277	        wizard.lastStep = true;
6278	      }
6279	    };
6280
6281	    wizard.enableFormFunctions = function () {
6282	      $$this.find('.form__section__edit, '+wizard.settings.submitHandle)
6283	          .not('.keep-disabled')
6284	        .attr('disabled', false)
6285	        .removeClass('disabled');
6286	    }
6287	    wizard.disableFormFunctions = function (step) {
6288	      $$this.find('.form__section__edit, '+wizard.settings.submitHandle)
6289	        .attr('disabled', true)
6290	        .addClass('disabled');
6291	    }
6292
6293	    /** binds validation to step **/
6294	    wizard.validateStep = function (step) {
6295	      var validationTarget = step.get(0);
6296	      var settings = wizard.validationSettings;
6297
6298	      // check if validation rules are set
6299	      if (typeof(wizard.settings.validation) !== 'undefined') {
6300	        var validation = wizard.settings.validation[validationTarget.id];
6301
6302	        if (typeof(validation) !== 'undefined') {
6303	          settings.rules = validation.rules;
6304	          settings.messages = validation.messages;
6305	        }
6306	      }
6307
6308	      step.validate(settings);
6309	    }
6310
6311	    /** enables all form elements and show form submit elements **/
6312	    wizard.enableStep = function (step) {
6313	      wizard.activeStep = step;
6314
6315	      $(step).find(wizard.formElements).not('.keep-disabled').attr('disabled', false);
6316
6317	      if ($(step).find('.form__section__edit').length > 0) {
6318	        $(step).find('button[type="submit"]').parent('div').show();
6319	      }
6320	    }
6321
6322	    /** disables all form elements and hides form submit elements **/
6323	    wizard.disableStep = function (step) {
6324	      wizard.activeStep = null;
6325
6326	      $(step).find(wizard.formElements).attr('disabled', true);
6327	      $(step).find('button[type="submit"]').parent('div').hide();
6328	    }
6329
6330	    /** adds edit elements **/
6331	    wizard.completeStep = function (step) {
6332
6333	      wizard.disableStep(step);
6334
6335	      if ($(step).is('form')) {
6336	        var editButton   = '<button type="button" class="form__section__edit">'+wizard.settings.translate.buttonEdit+'</button>',
6337	            cancelButton = '<button type="button" class="form__section__cancel">'+wizard.settings.translate.buttonCancel+'</button>';
6338	        // add edit button if not present
6339	        if ($(step).find('.form__section__edit').length <= 0) {
6340	          $(step).find('.form__section__header').append(editButton);
6341	        }
6342	        if ($(step).find('.form__section__cancel').length <= 0) {
6343	          $(step).find('button[type="submit"]').after(cancelButton);
6344	        }
6345	      }
6346	    }
6347
6348	    /** triggered by edit button
6349	    /** remove errors, disable active step, highlight edit step **/
6350	    wizard.editStep = function (step) {
6351	      wizard.activeStep = null;
6352	      wizard.settings.onEdit($$this, step);
6353
6354	      wizard.savedStep = step.html();
6355
6356	      // remove errors from current step
6357	      $(wizard.currentStep).find(wizard.formElements).removeClass('error');
6358	      $(wizard.currentStep).find('.error-box').remove();
6359
6360	      wizard.disableStep(wizard.currentStep);
6361	      wizard.disableFormFunctions(step);
6362	      wizard.enableStep(step);
6363	    }
6364
6365	    wizard.submitStep = function(step, callback) {
6366
6367	      var response = {
6368	        ok: true,
6369	        content: null
6370	      }
6371
6372	      // configure ajax submit here
6373	      // handle errors, response
6374
6375	      $(step).ajaxSubmit({
6376	        url: '/customer-evaluation/ajax/submit-step/',
6377	        beforeSend: function () {
6378	          $$this.find('button').attr('disabled', true);
6379	          if (wizard.settings.debug){
6380	            console.log('... submitting data');
6381	          }
6382	        },
6383	        success: function (data, statusMsg) {
6384	          // TODO: pass server success to response
6385	          response.ok = true;
6386	          response.content = data;
6387	        },
6388	        error: function (data, statusMsg) {
6389	          // TODO: pass server error message to response
6390	          console.log('ajax error')
6391	        },
6392	        complete: function () {
6393	          $$this.find('button').not('.keep-disabled').attr('disabled', false);
6394
6395	          // return response in callback function
6396	          if (typeof(callback) !== 'undefined' && typeof(callback) == 'function') {
6397	            callback(response);
6398	          }
6399	        }
6400	      });
6401	    }
6402
6403	    wizard.setup = function () {
6404
6405	      // find all elements
6406	      if (typeof (wizard.settings.elements) === 'undefined') {
6407	        wizard.elements = $$this.find(wizard.settings.elementHandle);
6408	      } else {
6409	        wizard.elements = $(wizard.settings.elements);
6410	        wizard.elements.addClass('wizard__step');
6411	      }
6412
6413	      // hide all elements, show startElement and all preceeding elements
6414	      // if window.location.hash set startstep accordingly
6415	      if ( typeof(window.location.hash) !== 'undefinded' && window.location.hash.length > 2) {
6416	        // check if hash is a wizard element
6417	        var windowHash = wizard.elements.filter(window.location.hash).length;
6418	        if (windowHash > 0) {
6419	          // overwrite startStep
6420	          wizard.settings.startStep = window.location.hash;
6421	        }
6422	      }
6423
6424	      // add binding
6425	      $$this.on('click', wizard.settings.submitHandle, function(e) {
6426	        e.preventDefault();
6427	        e.stopPropagation();
6428
6429	        var $$form = null;
6430	        if (wizard.currentStep.is('form')){
6431	          $$form = wizard.currentStep;
6432	        } else {
6433	          $$form = wizard.currentStep.find('form');
6434	        }
6435
6436	        if ($$form.length > 0) {
6437	          if (wizard.settings.validate){
6438
6439	            // check if form is valid and proceed
6440	            if($$form.valid()) {
6441
6442	              // if all steps are completed submit redirects to nextPage
6443	              if (wizard.lastStep && wizard.lastStepCompleted) {
6444
6445	                // placing the nextPage var in front of the hash
6446	                var newPath  = window.location.pathname.replace(/([0-9a-f]{32})(?=\/)/g, wizard.settings.nextPage+'/$1');
6447	                    //newPath += window.location.search;
6448	                    //newPath += window.location.hash;
6449
6450	                window.location = newPath;
6451	                return;
6452	              }
6453
6454	              // call laststep function and returns if last step
6455	              if (wizard.lastStep) {
6456	                wizard.settings.lastStep($$this, wizard.currentStep);
6457	                return;
6458	              }
6459
6460	              wizard.submitStep($$form, function (data) {
6461	                if (data.ok) {
6462	                  // show next step
6463	                  wizard.show(wizard.nextStep);
6464
6465	                  var newContent = $(data.content);
6466	                  $$form.replaceWith(newContent);
6467
6468	                  // add edit functionality to newContent
6469	                  wizard.completeStep(newContent);
6470
6471	                  wizard.enableFormFunctions();
6472
6473	                  if (!wizard.lastStepCompleted) {
6474	                    wizard.enableStep(wizard.currentStep);
6475	                  }
6476
6477
6478	                  // rebind validation
6479	                  wizard.validateStep(newContent);
6480	                }
6481	              });
6482	            }
6483	          }
6484	        } else {
6485	          // if its not a form but the last step, call lastStep function
6486	          if (wizard.lastStep) {
6487	            wizard.settings.lastStep($$this, wizard.currentStep);
6488	          }
6489	        }
6490	      });
6491
6492	      $$this.on('submit', wizard.activeStep, function (e) {
6493	        e.preventDefault();
6494	        e.stopPropagation();
6495
6496	        if (wizard.settings.validate){
6497
6498	          // check if form is valid and proceed
6499	          if(wizard.activeStep.valid()) {
6500
6501	            wizard.submitStep(wizard.activeStep, function (data) {
6502
6503	              if (data.ok) {
6504	                var newContent = $(data.content);
6505	                wizard.activeStep.replaceWith(newContent);
6506
6507	                // add edit functionality to newContent
6508	                wizard.completeStep(newContent);
6509
6510	                wizard.enableFormFunctions();
6511
6512	                // highlight step active before edit
6513	                if (!wizard.lastStepCompleted) {
6514	                  wizard.enableStep(wizard.currentStep);
6515	                }
6516	                // rebind validation
6517	                wizard.validateStep(newContent);
6518	              }
6519	            });
6520	          }
6521	        }
6522	      });
6523
6524	      // bind click event to edit button
6525	      $$this.on('click', '.form__section__edit', function (e) {
6526	        var sourceStep = $(this).parents('form');
6527	        e.preventDefault();
6528	        e.stopPropagation();
6529
6530	        wizard.editStep(sourceStep);
6531	      });
6532
6533
6534	      // bind click event to cancel button
6535	      $('body').on('click', '.form__section__cancel', function (e) {
6536	        e.preventDefault();
6537	        e.stopPropagation();
6538
6539	        wizard.activeStep.html(wizard.savedStep);
6540	        wizard.savedStep = null;
6541	        wizard.settings.onEditCancel($$this, wizard.activeStep);
6542
6543	        // disable edit functionality & enable currentStep which is not completed yet
6544	        wizard.disableStep(wizard.activeStep);
6545
6546	        wizard.enableFormFunctions();
6547	        if (!wizard.lastStepCompleted) {
6548	          wizard.enableStep(wizard.currentStep);
6549	        }
6550	      });
6551
6552	      // bind validation
6553	      $.each(wizard.elements, function (i, element) {
6554	        if (typeof(element !== 'undefined')) {
6555	          var $$element = $(element);
6556
6557	          // hide submit button
6558	          $$element.find('[type="submit"]').parent('div').hide();
6559
6560	          // call calidation
6561	          wizard.validateStep($$element);
6562	        }
6563	      })
6564
6565	      // init wizard steps
6566	      if (wizard.elements.filter(wizard.settings.startStep).length <= 0 || wizard.settings.startStep == ':first') {
6567	        wizard.currentStep = wizard.elements.filter(':first');
6568	      } else {
6569	        // startStep = last finished step, so define the following step as currentStep
6570	        wizard.currentStep = wizard.elements.filter(wizard.settings.startStep).next(wizard.settings.elementHandle);
6571	        if (wizard.currentStep.length <= 0) {
6572	          wizard.lastStepCompleted = true;
6573	          wizard.currentStep = wizard.elements.filter(wizard.settings.startStep);
6574	        }
6575	      }
6576
6577	      wizard.nextStep = wizard.elements.filter(wizard.currentStep).next(wizard.settings.elementHandle);
6578	      if (wizard.nextStep.length <= 0) {
6579	        wizard.lastStep = true;
6580	      }
6581
6582	      if (wizard.lastStep && wizard.lastStepCompleted) {
6583	        wizard.elements.each(function () {
6584	          wizard.completeStep(this);
6585	        });
6586	      } else {
6587	        wizard.elements.hide()
6588	          .filter(wizard.currentStep).show()
6589	          .prevAll(wizard.settings.elementHandle).each(function () {
6590	            $(this).show();
6591	            wizard.completeStep(this);
6592	          })
6593	      }
6594
6595	      //wizard.enableStep(wizard.currentStep);
6596	      //wizard.editStep(wizard.currentStep);
6597
6598	      // APPEND SUBMIT
6599	      // check if a submitHandle is defined
6600	      if (wizard.settings.submitHandle === null || wizard.settings.submitHtml === null) {
6601	        // use default submit elements
6602	        $$this.append(wizard.defaultSubmitHtml);
6603	        wizard.settings.submitHandle = wizard.defaultSubmitHandle;
6604	      } else {
6605	        // append custom submit elements
6606	        $$this.append(wizard.settings.submitHtml);
6607	      }
6608
6609
6610	    }
6611
6612	    wizard.setup();
6613	    return $$this;
6614	  };
6615	})(jQuery);
6616
6617/***/ }),
6618
6619/***/ 318:
6620/***/ (function(module, exports) {
6621
6622	// as seen here http://stackoverflow.com/questions/18422223/bootstrap-3-modal-vertical-position-center
6623	function adjustModalMaxHeightAndPosition(){
6624	  $('.modal').each(function(){
6625	    if($(this).hasClass('in') === false){
6626	      $(this).show(); /* Need this to get modal dimensions */
6627	    }
6628	    var contentHeight = $(window).height() - 60;
6629	    var headerHeight = $(this).find('.modal-header').outerHeight() || 2;
6630	    var footerHeight = $(this).find('.modal-footer').outerHeight() || 2;
6631
6632	    $(this).find('.modal-content').css({
6633	      'max-height': function () {
6634	        return contentHeight;
6635	      }
6636	    });
6637
6638	    $(this).find('.modal-body').css({
6639	      'max-height': function () {
6640	        return (contentHeight - (headerHeight + footerHeight));
6641	      }
6642	    });
6643
6644	    $(this).find('.modal-dialog').addClass('modal-dialog-center').css({
6645	      'margin-top': function () {
6646	        return -($(this).outerHeight() / 2);
6647	      },
6648	      'margin-left': function () {
6649	        return -($(this).outerWidth() / 2);
6650	      }
6651	    });
6652	    if($(this).hasClass('in') === false){
6653	      $(this).hide(); /* Hide modal */
6654	    }
6655	  });
6656	}
6657	if ($(window).height() >= 320){
6658	  $(window).resize(adjustModalMaxHeightAndPosition).trigger("resize");
6659	}
6660
6661/***/ }),
6662
6663/***/ 319:
6664/***/ (function(module, exports, __webpack_require__) {
6665
6666	var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/**
6667	 * bootbox.js [v4.2.0]
6668	 *
6669	 * http://bootboxjs.com/license.txt
6670	 */
6671
6672	// @see https://github.com/makeusabrew/bootbox/issues/180
6673	// @see https://github.com/makeusabrew/bootbox/issues/186
6674	(function (root, factory) {
6675
6676	  "use strict";
6677	  if (true) {
6678	    // AMD. Register as an anonymous module.
6679	    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(270)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
6680	  } else if (typeof exports === "object") {
6681	    // Node. Does not work with strict CommonJS, but
6682	    // only CommonJS-like environments that support module.exports,
6683	    // like Node.
6684	    module.exports = factory(require("jquery"));
6685	  } else {
6686	    // Browser globals (root is window)
6687	    root.bootbox = factory(root.jQuery);
6688	  }
6689
6690	}(this, function init($, undefined) {
6691
6692	  "use strict";
6693
6694	  // the base DOM structure needed to create a modal
6695	  var templates = {
6696	    dialog:
6697	      "<div class='bootbox modal' tabindex='-1' role='dialog'>" +
6698	        "<div class='modal-dialog'>" +
6699	          "<div class='modal-content'>" +
6700	            "<div class='modal-body'><div class='bootbox-body'></div></div>" +
6701	          "</div>" +
6702	        "</div>" +
6703	      "</div>",
6704	    header:
6705	      "<div class='modal-header'>" +
6706	        "<h4 class='modal-title'></h4>" +
6707	      "</div>",
6708	    footer:
6709	      "<div class='modal-footer'></div>",
6710	    closeButton:
6711	      "<button type='button' class='bootbox-close-button close' data-dismiss='modal' aria-hidden='true'>&times;</button>",
6712	    form:
6713	      "<form class='bootbox-form'></form>",
6714	    inputs: {
6715	      text:
6716	        "<input class='bootbox-input bootbox-input-text form-control' autocomplete=off type=text />",
6717	      textarea:
6718	        "<textarea class='bootbox-input bootbox-input-textarea form-control'></textarea>",
6719	      email:
6720	        "<input class='bootbox-input bootbox-input-email form-control' autocomplete='off' type='email' />",
6721	      select:
6722	        "<select class='bootbox-input bootbox-input-select form-control'></select>",
6723	      checkbox:
6724	        "<div class='checkbox'><label>
6724<input class='bootbox-input bootbox-input-checkbox' type='checkbox' /></label></div>",
6725	      date:
6726	        "<input class='bootbox-input bootbox-input-date form-control' autocomplete=off type='date' />",
6727	      time:
6728	        "<input class='bootbox-input bootbox-input-time form-control' autocomplete=off type='time' />",
6729	      number:
6730	        "<input class='bootbox-input bootbox-input-number form-control' autocomplete=off type='number' />",
6731	      password:
6732	        "<input class='bootbox-input bootbox-input-password form-control' autocomplete='off' type='password' />"
6733	    }
6734	  };
6735
6736	  var defaults = {
6737	    // default language
6738	    locale: "en",
6739	    // show backdrop or not
6740	    backdrop: true,
6741	    // animate the modal in/out
6742	    animate: true,
6743	    // additional class string applied to the top level dialog
6744	    className: null,
6745	    // whether or not to include a close button
6746	    closeButton: true,
6747	    // show the dialog immediately by default
6748	    show: true,
6749	    // dialog container
6750	    container: "body"
6751	  };
6752
6753	  // our public object; augmented after our private API
6754	  var exports = {};
6755
6756	  /**
6757	   * @private
6758	   */
6759	  function _t(key) {
6760	    var locale = locales[defaults.locale];
6761	    return locale ? locale[key] : locales.en[key];
6762	  }
6763
6764	  function processCallback(e, dialog, callback) {
6765	    e.stopPropagation();
6766	    e.preventDefault();
6767
6768	    // by default we assume a callback will get rid of the dialog,
6769	    // although it is given the opportunity to override this
6770
6771	    // so, if the callback can be invoked and it *explicitly returns false*
6772	    // then we'll set a flag to keep the dialog active...
6773	    var preserveDialog = $.isFunction(callback) && callback(e) === false;
6774
6775	    // ... otherwise we'll bin it
6776	    if (!preserveDialog) {
6777	      dialog.modal("hide");
6778	    }
6779	  }
6780
6781	  function getKeyLength(obj) {
6782	    // @TODO defer to Object.keys(x).length if available?
6783	    var k, t = 0;
6784	    for (k in obj) {
6785	      t ++;
6786	    }
6787	    return t;
6788	  }
6789
6790	  function each(collection, iterator) {
6791	    var index = 0;
6792	    $.each(collection, function(key, value) {
6793	      iterator(key, value, index++);
6794	    });
6795	  }
6796
6797	  function sanitize(options) {
6798	    var buttons;
6799	    var total;
6800
6801	    if (typeof options !== "object") {
6802	      throw new Error("Please supply an object of options");
6803	    }
6804
6805	    if (!options.message) {
6806	      throw new Error("Please specify a message");
6807	    }
6808
6809	    // make sure any supplied options take precedence over defaults
6810	    options = $.extend({}, defaults, options);
6811
6812	    if (!options.buttons) {
6813	      options.buttons = {};
6814	    }
6815
6816	    // we only support Bootstrap's "static" and false backdrop args
6817	    // supporting true would mean you could dismiss the dialog without
6818	    // explicitly interacting with it
6819	    options.backdrop = options.backdrop ? "static" : false;
6820
6821	    buttons = options.buttons;
6822
6823	    total = getKeyLength(buttons);
6824
6825	    each(buttons, function(key, button, index) {
6826
6827	      if ($.isFunction(button)) {
6828	        // short form, assume value is our callback. Since button
6829	        // isn't an object it isn't a reference either so re-assign it
6830	        button = buttons[key] = {
6831	          callback: button
6832	        };
6833	      }
6834
6835	      // before any further checks make sure by now button is the correct type
6836	      if ($.type(button) !== "object") {
6837	        throw new Error("button with key " + key + " must be an object");
6838	      }
6839
6840	      if (!button.label) {
6841	        // the lack of an explicit label means we'll assume the key is good enough
6842	        button.label = key;
6843	      }
6844
6845	      if (!button.className) {
6846	        if (total <= 2 && index === total-1) {
6847	          // always add a primary to the main option in a two-button dialog
6848	          button.className = "btn-primary";
6849	        } else {
6850	          button.className = "btn-default";
6851	        }
6852	      }
6853	    });
6854
6855	    return options;
6856	  }
6857
6858	  /**
6859	   * map a flexible set of arguments into a single returned object
6860	   * if args.length is already one just return it, otherwise
6861	   * use the properties argument to map the unnamed args to
6862	   * object properties
6863	   * so in the latter case:
6864	   * mapArguments(["foo", $.noop], ["message", "callback"])
6865	   * -> { message: "foo", callback: $.noop }
6866	   */
6867	  function mapArguments(args, properties) {
6868	    var argn = args.length;
6869	    var options = {};
6870
6871	    if (argn < 1 || argn > 2) {
6872	      throw new Error("Invalid argument length");
6873	    }
6874
6875	    if (argn === 2 || typeof args[0] === "string") {
6876	      options[properties[0]] = args[0];
6877	      options[properties[1]] = args[1];
6878	    } else {
6879	      options = args[0];
6880	    }
6881
6882	    return options;
6883	  }
6884
6885	  /**
6886	   * merge a set of default dialog options with user supplied arguments
6887	   */
6888	  function mergeArguments(defaults, args, properties) {
6889	    return $.extend(
6890	      // deep merge
6891	      true,
6892	      // ensure the target is an empty, unreferenced object
6893	      {},
6894	      // the base options object for this type of dialog (often just buttons)
6895	      defaults,
6896	      // args could be an object or array; if it's an array properties will
6897	      // map it to a proper options object
6898	      mapArguments(
6899	        args,
6900	        properties
6901	      )
6902	    );
6903	  }
6904
6905	  /**
6906	   * this entry-level method makes heavy use of composition to take a simple
6907	   * range of inputs and return valid options suitable for passing to bootbox.dialog
6908	   */
6909	  function mergeDialogOptions(className, labels, properties, args) {
6910	    //  build up a base set of dialog properties
6911	    var baseOptions = {
6912	      className: "bootbox-" + className,
6913	      buttons: createLabels.apply(null, labels)
6914	    };
6915
6916	    // ensure the buttons properties generated, *after* merging
6917	    // with user args are still valid against the supplied labels
6918	    return validateButtons(
6919	      // merge the generated base properties with user supplied arguments
6920	      mergeArguments(
6921	        baseOptions,
6922	        args,
6923	        // if args.length > 1, properties specify how each arg maps to an object key
6924	        properties
6925	      ),
6926	      labels
6927	    );
6928	  }
6929
6930	  /**
6931	   * from a given list of arguments return a suitable object of button labels
6932	   * all this does is normalise the given labels and translate them where possible
6933	   * e.g. "ok", "confirm" -> { ok: "OK, cancel: "Annuleren" }
6934	   */
6935	  function createLabels() {
6936	    var buttons = {};
6937
6938	    for (var i = 0, j = arguments.length; i < j; i++) {
6939	      var argument = arguments[i];
6940	      var key = argument.toLowerCase();
6941	      var value = argument.toUpperCase();
6942
6943	      buttons[key] = {
6944	        label: _t(value)
6945	      };
6946	    }
6947
6948	    return buttons;
6949	  }
6950
6951	  function validateButtons(options, buttons) {
6952	    var allowedButtons = {};
6953	    each(buttons, function(key, value) {
6954	      allowedButtons[value] = true;
6955	    });
6956
6957	    each(options.buttons, function(key) {
6958	      if (allowedButtons[key] === undefined) {
6959	        throw new Error("button key " + key + " is not allowed (options are " + buttons.join("\n") + ")");
6960	      }
6961	    });
6962
6963	    return options;
6964	  }
6965
6966	  exports.alert = function() {
6967	    var options;
6968
6969	    options = mergeDialogOptions("alert", ["ok"], ["message", "callback"], arguments);
6970
6971	    if (options.callback && !$.isFunction(options.callback)) {
6972	      throw new Error("alert requires callback property to be a function when provided");
6973	    }
6974
6975	    /**
6976	     * overrides
6977	     */
6978	    options.buttons.ok.callback = options.onEscape = function() {
6979	      if ($.isFunction(options.callback)) {
6980	        return options.callback();
6981	      }
6982	      return true;
6983	    };
6984
6985	    return exports.dialog(options);
6986	  };
6987
6988	  exports.confirm = function() {
6989	    var options;
6990
6991	    options = mergeDialogOptions("confirm", ["cancel", "confirm"], ["message", "callback"], arguments);
6992
6993	    /**
6994	     * overrides; undo anything the user tried to set they shouldn't have
6995	     */
6996	    options.buttons.cancel.callback = options.onEscape = function() {
6997	      return options.callback(false);
6998	    };
6999
7000	    options.buttons.confirm.callback = function() {
7001	      return options.callback(true);
7002	    };
7003
7004	    // confirm specific validation
7005	    if (!$.isFunction(options.callback)) {
7006	      throw new Error("confirm requires a callback");
7007	    }
7008
7009	    return exports.dialog(options);
7010	  };
7011
7012	  exports.prompt = function() {
7013	    var options;
7014	    var defaults;
7015	    var dialog;
7016	    var form;
7017	    var input;
7018	    var shouldShow;
7019	    var inputOptions;
7020
7021	    // we have to create our form first otherwise
7022	    // its value is undefined when gearing up our options
7023	    // @TODO this could be solved by allowing message to
7024	    // be a function instead...
7025	    form = $(templates.form);
7026
7027	    // prompt defaults are more complex than others in that
7028	    // users can override more defaults
7029	    // @TODO I don't like that prompt has to do a lot of heavy
7030	    // lifting which mergeDialogOptions can *almost* support already
7031	    // just because of 'value' and 'inputType' - can we refactor?
7032	    defaults = {
7033	      className: "bootbox-prompt",
7034	      buttons: createLabels("cancel", "confirm"),
7035	      value: "",
7036	      inputType: "text"
7037	    };
7038
7039	    options = validateButtons(
7040	      mergeArguments(defaults, arguments, ["title", "callback"]),
7041	      ["cancel", "confirm"]
7042	    );
7043
7044	    // capture the user's show value;
7044 we always set this to false before
7045	    // spawning the dialog to give us a chance to attach some handlers to
7046	    // it, but we need to make sure we respect a preference not to show it
7047	    shouldShow = (options.show === undefined) ? true : options.show;
7048
7049	    // check if the browser supports the option.inputType
7050	    var html5inputs = ["date","time","number"];
7051	    var i = document.createElement("input");
7052	    i.setAttribute("type", options.inputType);
7053	    if(html5inputs[options.inputType]){
7054	      options.inputType = i.type;
7055	    }
7056
7057	    /**
7058	     * overrides; undo anything the user tried to set they shouldn't have
7059	     */
7060	    options.message = form;
7061
7062	    options.buttons.cancel.callback = options.onEscape = function() {
7063	      return options.callback(null);
7064	    };
7065
7066	    options.buttons.confirm.callback = function() {
7067	      var value;
7068
7069	      switch (options.inputType) {
7070	        case "text":
7071	        case "textarea":
7072	        case "email":
7073	        case "select":
7074	        case "date":
7075	        case "time":
7076	        case "number":
7077	        case "password":
7078	          value = input.val();
7079	          break;
7080
7081	        case "checkbox":
7082	          var checkedItems = input.find("input:checked");
7083
7084	          // we assume that checkboxes are always multiple,
7085	          // hence we default to an empty array
7086	          value = [];
7087
7088	          each(checkedItems, function(_, item) {
7089	            value.push($(item).val());
7090	          });
7091	          break;
7092	      }
7093
7094	      return options.callback(value);
7095	    };
7096
7097	    options.show = false;
7098
7099	    // prompt specific validation
7100	    if (!options.title) {
7101	      throw new Error("prompt requires a title");
7102	    }
7103
7104	    if (!$.isFunction(options.callback)) {
7105	      throw new Error("prompt requires a callback");
7106	    }
7107
7108	    if (!templates.inputs[options.inputType]) {
7109	      throw new Error("invalid prompt type");
7110	    }
7111
7112	    // create the input based on the supplied type
7113	    input = $(templates.inputs[options.inputType]);
7114
7115	    switch (options.inputType) {
7116	      case "text":
7117	      case "textarea":
7118	      case "email":
7119	      case "date":
7120	      case "time":
7121	      case "number":
7122	      case "password":
7123	        input.val(options.value);
7124	        break;
7125
7126	      case "select":
7127	        var groups = {};
7128	        inputOptions = options.inputOptions || [];
7129
7130	        if (!inputOptions.length) {
7131	          throw new Error("prompt with select requires options");
7132	        }
7133
7134	        each(inputOptions, function(_, option) {
7135
7136	          // assume the element to attach to is the input...
7137	          var elem = input;
7138
7139	          if (option.value === undefined || option.text === undefined) {
7140	            throw new Error("given options in wrong format");
7141	          }
7142
7143
7144	          // ... but override that element if this option sits in a group
7145
7146	          if (option.group) {
7147	            // initialise group if necessary
7148	            if (!groups[option.group]) {
7149	              groups[option.group] = $("<optgroup/>").attr("label", option.group);
7150	            }
7151
7152	            elem = groups[option.group];
7153	          }
7154
7155	          elem.append("<option value='" + option.value + "'>" + option.text + "</option>");
7156	        });
7157
7158	        each(groups, function(_, group) {
7159	          input.append(group);
7160	        });
7161
7162	        // safe to set a select's value as per a normal input
7163	        input.val(options.value);
7164	        break;
7165
7166	      case "checkbox":
7167	        var values   = $.isArray(options.value) ? options.value : [options.value];
7168	        inputOptions = options.inputOptions || [];
7169
7170	        if (!inputOptions.length) {
7171	          throw new Error("prompt with checkbox requires options");
7172	        }
7173
7174	        if (!inputOptions[0].value || !inputOptions[0].text) {
7175	          throw new Error("given options in wrong format");
7176	        }
7177
7178	        // checkboxes have to nest within a containing element, so
7179	        // they break the rules a bit and we end up re-assigning
7180	        // our 'input' element to this container instead
7181	        input = $("<div/>");
7182
7183	        each(inputOptions, function(_, option) {
7184	          var checkbox = $(templates.inputs[options.inputType]);
7185
7186	          checkbox.find("input").attr("value", option.value);
7187	          checkbox.find("label").append(option.text);
7188
7189	          // we've ensured values is an array so we can always iterate over it
7190	          each(values, function(_, value) {
7191	            if (value === option.value) {
7192	              checkbox.find("input").prop("checked", true);
7193	            }
7194	          });
7195
7196	          input.append(checkbox);
7197	        });
7198	        break;
7199	    }
7200
7201	    if (options.placeholder) {
7202	      input.attr("placeholder", options.placeholder);
7203	    }
7204
7205	    if(options.pattern){
7206	      input.attr("pattern", options.pattern);
7207	    }
7208
7209	    // now place it in our form
7210	    form.append(input);
7211
7212	    form.on("submit", function(e) {
7213	      e.preventDefault();
7214	      // @TODO can we actually click *the* button object instead?
7215	      // e.g. buttons.confirm.click() or similar
7216	      dialog.find(".btn-primary").click();
7217	    });
7218
7219	    dialog = exports.dialog(options);
7220
7221	    // clear the existing handler focusing the submit button...
7222	    dialog.off("shown.bs.modal");
7223
7224	    // ...and replace it with one focusing our input, if possible
7225	    dialog.on("shown.bs.modal", function() {
7226	      input.focus();
7227	    });
7228
7229	    if (shouldShow === true) {
7230	      dialog.modal("show");
7231	    }
7232
7233	    return dialog;
7234	  };
7235
7236	  exports.dialog = function(options) {
7237	    options = sanitize(options);
7238
7239	    var dialog = $(templates.dialog);
7240	    var body = dialog.find(".modal-body");
7241	    var buttons = options.buttons;
7242	    var buttonStr = "";
7243	    var callbacks = {
7244	      onEscape: options.onEscape
7245	    };
7246
7247	    each(buttons, function(key, button) {
7248
7249	      // @TODO I don't like this string appending to itself; bit dirty. Needs reworking
7250	      // can we just build up button elements instead? slower but neater. Then button
7251	      // can just become a template too
7252	      buttonStr += "<button data-bb-handler='" + key + "' type='button' class='btn " + button.className + "'>" + button.label + "</button>";
7253	      callbacks[key] = button.callback;
7254	    });
7255
7256	    body.find(".bootbox-body").html(options.message);
7257
7258	    if (options.animate === true) {
7259	      dialog.addClass("fade");
7260	    }
7261
7262	    if (options.className) {
7263	      dialog.addClass(options.className);
7264	    }
7265
7266	    if (options.title) {
7267	      body.before(templates.header);
7268	    }
7269
7270	    if (options.closeButton) {
7271	      var closeButton = $(templates.closeButton);
7272
7273	      if (options.title) {
7274	        dialog.find(".modal-header").prepend(closeButton);
7275	      } else {
7276	        closeButton.css("margin-top", "-10px").prependTo(body);
7277	      }
7278	    }
7279
7280	    if (options.title) {
7281	      dialog.find(".modal-title").html(options.title);
7282	    }
7283
7284	    if (buttonStr.length) {
7285	      body.after(templates.footer);
7286	      dialog.find(".modal-footer").html(buttonStr);
7287	    }
7288
7289
7290	    /**
7291	     * Bootstrap event listeners; used handle extra
7292	     * setup & teardown required after the underlying
7293	     * modal has performed certain actions
7294	     */
7295
7296	    dialog.on("hidden.bs.modal", function(e) {
7297	      // ensure we don't accidentally intercept hidden events triggered
7298	      // by children of the current dialog. We shouldn't anymore now BS
7299	      // namespaces its events; but still worth doing
7300	      if (e.target === this) {
7301	        dialog.remove();
7302	      }
7303	    });
7304
7305	    /*
7306	    dialog.on("show.bs.modal", function() {
7307	      // sadly this doesn't work; show is called *just* before
7308	      // the backdrop is added so we'd need a setTimeout hack or
7309	      // otherwise... leaving in as would be nice
7310	      if (options.backdrop) {
7311	        dialog.next(".modal-backdrop").addClass("bootbox-backdrop");
7312	      }
7313	    });
7314	    */
7315
7316	    dialog.on("shown.bs.modal", function() {
7317	      dialog.find(".btn-primary:first").focus();
7318	    });
7319
7320	    /**
7321	     * Bootbox event listeners; experimental and may not last
7322	     * just an attempt to decouple some behaviours from their
7323	     * respective triggers
7324	     */
7325
7326	    dialog.on("escape.close.bb", function(e) {
7327	      if (callbacks.onEscape) {
7328	        processCallback(e, dialog, callbacks.onEscape);
7329	      }
7330	    });
7331
7332	    /**
7333	     * Standard jQuery event listeners; used to handle user
7334	     * interaction with our dialog
7335	     */
7336
7337	    dialog.on("click", ".modal-footer button", function(e) {
7338	      var callbackKey = $(this).data("bb-handler");
7339
7340	      processCallback(e, dialog, callbacks[callbackKey]);
7341
7342	    });
7343
7344	    dialog.on("click", ".bootbox-close-button", function(e) {
7345	      // onEscape might be falsy but that's fine; the fact is
7346	      // if the user has managed to click the close button we
7347	      // have to close the dialog, callback or not
7348	      processCallback(e, dialog, callbacks.onEscape);
7349	    });
7350
7351	    dialog.on("keyup", function(e) {
7352	      if (e.which === 27) {
7353	        dialog.trigger("escape.close.bb");
7354	      }
7355	    });
7356
7357	    // the remainder of this method simply deals with adding our
7358	    // dialogent to the DOM, augmenting it with Bootstrap's modal
7359	    // functionality and then giving the resulting object back
7360	    // to our caller
7361
7362	    $(options.container).append(dialog);
7363
7364	    dialog.modal({
7365	      backdrop: options.backdrop,
7366	      keyboard: false,
7367	      show: false
7368	    });
7369
7370	    if (options.show) {
7371	      dialog.modal("show");
7372	    }
7373
7374	    // @TODO should we return the raw element here or should
7375	    // we wrap it in an object on which we can expose some neater
7376	    // methods, e.g. var d = bootbox.alert(); d.hide(); instead
7377	    // of d.modal("hide");
7378
7379	   /*
7380	    function BBDialog(elem) {
7381	      this.elem = elem;
7382	    }
7383
7384	    BBDialog.prototype = {
7385	      hide: function() {
7386	        return this.elem.modal("hide");
7387	      },
7388	      show: function() {
7389	        return this.elem.modal("show");
7390	      }
7391	    };
7392	    */
7393
7394	    return dialog;
7395
7396	  };
7397
7398	  exports.setDefaults = function() {
7399	    var values = {};
7400
7401	    if (arguments.length === 2) {
7402	      // allow passing of single key/value...
7403	      values[arguments[0]] = arguments[1];
7404	    } else {
7405	      // ... and as an object too
7406	      values = arguments[0];
7407	    }
7408
7409	    $.extend(defaults, values);
7410	  };
7411
7412	  exports.hideAll = function() {
7413	    $(".bootbox").modal("hide");
7414	  };
7415
7416
7417	  /**
7418	   * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are
7419	   * unlikely to be required. If this gets too large it can be split out into separate JS files.
7420	   */
7421	  var locales = {
7422	    br : {
7423	      OK      : "OK",
7424	      CANCEL  : "Cancelar",
7425	      CONFIRM : "Sim"
7426	    },
7427	    da : {
7428	      OK      : "OK",
7429	      CANCEL  : "Annuller",
7430	      CONFIRM : "Accepter"
7431	    },
7432	    de : {
7433	      OK      : "OK",
7434	      CANCEL  : "Abbrechen",
7435	      CONFIRM : "Akzeptieren"
7436	    },
7437	    en : {
7438	      OK      : "OK",
7439	      CANCEL  : "Cancel",
7440	      CONFIRM : "OK"
7441	    },
7442	    es : {
7443	      OK      : "OK",
7444	      CANCEL  : "Cancelar",
7445	      CONFIRM : "Aceptar"
7446	    },
7447	    fi : {
7448	      OK      : "OK",
7449	      CANCEL  : "Peruuta",
7450	      CONFIRM : "OK"
7451	    },
7452	    fr : {
7453	      OK      : "OK",
7454	      CANCEL  : "Annuler",
7455	      CONFIRM : "D'accord"
7456	    },
7457	    he : {
7458	      OK      : "אישור",
7459	      CANCEL  : "ביטול",
7460	      CONFIRM : "אישור"
7461	    },
7462	    it : {
7463	      OK      : "OK",
7464	      CANCEL  : "Annulla",
7465	      CONFIRM : "Conferma"
7466	    },
7467	    lt : {
7468	      OK      : "Gerai",
7469	      CANCEL  : "Atšaukti",
7470	      CONFIRM : "Patvirtinti"
7471	    },
7472	    lv : {
7473	      OK      : "Labi",
7474	      CANCEL  : "Atcelt",
7475	      CONFIRM : "Apstiprināt"
7476	    },
7477	    nl : {
7478	      OK      : "OK",
7479	      CANCEL  : "Annuleren",
7480	      CONFIRM : "Accepteren"
7481	    },
7482	    no : {
7483	      OK      : "OK",
7484	      CANCEL  : "Avbryt",
7485	      CONFIRM : "OK"
7486	    },
7487	    pl : {
7488	      OK      : "OK",
7489	      CANCEL  : "Anuluj",
7490	      CONFIRM : "Potwierdź"
7491	    },
7492	    ru : {
7493	      OK      : "OK",
7494	      CANCEL  : "Отмена",
7495	      CONFIRM : "Применить"
7496	    },
7497	    sv : {
7498	      OK      : "OK",
7499	      CANCEL  : "Avbryt",
7500	      CONFIRM : "OK"
7501	    },
7502	    tr : {
7503	      OK      : "Tamam",
7504	      CANCEL  : "İptal",
7505	      CONFIRM : "Onayla"
7506	    },
7507	    zh_CN : {
7508	      OK      : "OK",
7509	      CANCEL  : "取消",
7510	      CONFIRM : "确认"
7511	    },
7512	    zh_TW : {
7513	      OK      : "OK",
7514	      CANCEL  : "取消",
7515	      CONFIRM : "確認"
7516	    }
7517	  };
7518
7519	  exports.init = function(_$) {
7520	    return init(_$ || $);
7521	  };
7522
7523	  return exports;
7524	}));
7525
7526
7527/***/ }),
7528
7529/***/ 320:
7530/***/ (function(module, exports) {
7531
7532	var carModel = {
7533
7534	  init: function( settings ){
7535	    carModel.config = {
7536	      partClass: 'carmodel__part',
7537	      parts: $('.carmodel__part').not('.carmodel__part--disabled'),
7538	      modal: $('#popover'),
7539	      damagePrefix: 'damage--',
7540	      clearAllHandle: null,
7541	      setdamageURL: '/customer-evaluation/ajax/record-damage/',
7542	      removedamageURL: '/customer-evaluation/ajax/remove-damage/',
7543	      removeAllDamagesURL: '/customer-evaluation/ajax/remove-all-damages/',
7544	      errorMessages: { 'damage_type' : 'please specify a damage' }
7545	    };
7546
7547	    $.extend( carModel.config, settings );
7548
7549	    carModel.setup();
7550	  },
7551
7552	  setup: function() {
7553
7554	    carModel.currentLeadId = carModel.config.modal.find('form').data('leadid');
7555
7556	    carModel.config.parts.each(function() {
7557	      // attach bootstrap tooltips
7558	      $(this).tooltip({
7559	        container: 'body'
7560	      });
7561
7562	      // attach bootstrap modal handler
7563	      var modalID = carModel.config.modal.attr('id');
7564	      $(this).attr({
7565	        'data-toggle': 'modal',
7566	        'data-target': '#' + modalID,
7567	      });
7568	    });
7569
7570	    carModel.config.modal
7571	      .modal({
7572	        backdrop: true,
7573	        show: false
7574	      })
7575	      .on('show.bs.modal', function(e) {
7576	        carModel.formPopulate(e.relatedTarget);
7577	      });
7578
7579	    carModel.config.modal.find('form')
7580	        .validate({
7581	          errorClass: 'damage__form__error',
7582	          errorElement: 'div',
7583	          errorPlacement: function(error, element) {
7584	            var parent = $(element).parent();
7585	            error.insertBefore(parent);
7586	          },
7587	          submitHandler: function() {
7588	            carModel.formSubmit();
7589	          },
7590	          messages: carModel.config.errorMessages
7591	        });
7592
7593	     carModel.config.modal.find( $('button[data-dismiss="damage"]') )
7594	       .on('click', function() {
7595	         var partId = carModel.config.modal.data('partid');
7596
7597	         carModel.clearDamage(partId);
7598	       });
7599
7600	     if (typeof (carModel.config.clearAllHandle) !== null) {
7601	       $(carModel.config.clearAllHandle).show().on('click', function (e) {
7602	         e.preventDefault();
7603	         e.stopPropagation();
7604
7605	         carModel.clearAllDamages();
7606	       });
7607	     }
7608	  },
7609
7610	  formPopulate: function(part) {
7611	    var $$this      = carModel.config.modal,
7612	        $$form      = $$this.find('form'),
7613	        $$part      = $(part),
7614
7615	        _partId     = $$part.data('partid'),
7616	        _title      = $$part.data('title'),
7617	        _damageType = $$part.data('damagetype'),
7618	        _damageDesc = $$part.data('damagedesc');
7619
7620	    $$this.data('partid', _partId);
7621	    $$this.find('.damage__form__title').text(_title);
7622
7623	    // reset formfields
7624	    $$this.find( $('button[data-dismiss="damage"]') ).addClass('hidden');
7625	    $$form.find('textarea').val('');
7626	    $$form.find('div.damage__form__error').remove();
7627	    $$form.find('input[type=radio]').prop('checked', false );
7628
7629	    //console.log(_partId + ' ' + _damageType)
7630
7631	    if ( typeof _damageType !== 'undefined' ) {
7632	      $$this.find( $('button[data-dismiss="damage"]') ).removeClass('hidden');
7633	      $$form.find('input[value='+ _damageType +']').prop('checked', true);
7634	    }
7635	    if ( typeof _damageDesc !== 'undefined' ) {
7636	      $$form.find('textarea').val(_damageDesc);
7637	    }
7638	    //getDamages
7639
7640
7641	  },
7642
7643	  formSubmit: function() {
7644	    var fields = carModel.formGatherValues();
7645
7646	    carModel.setDamage({
7647	      part: fields.part,
7648	      type: fields.damage_type,
7649	      desc: fields.damage_desc
7650	    });
7651	  },
7652
7653	  formGatherValues: function() {
7654	    var $$form      = carModel.config.modal.find('form'),
7655	    formValues      = $$form.serializeObject();
7656
7657	    formValues.part = carModel.config.modal.data('partid');
7658
7659	    return formValues;
7660	  },
7661
7662	  setDamage: function(damage) {
7663
7664	    // ajax stuff
7665	    var params = {
7666	      lead_hash: carModel.currentLeadId,
7667	      part_name: damage.part,
7668	      customer_damage_id: damage.type,
7669	      customer_description: damage.desc
7670	    };
7671
7672	    $.post(carModel.config.setdamageURL, params , function(data) {
7673	      // todo: loading
7674
7675	      if ( data.ok ) {
7676	        carModel.updatePart(damage);
7677	        carModel.config.modal.modal('hide');
7678	        carModel.updateView(damage);
7679	      } else {
7680	        console.error(data);
7681	        console.error('something went wrong');
7682	      }
7683	    });
7684	  },
7685
7686	  clearDamage: function(part) {
7687	    // ajax stuff
7688	    var params = {
7689	      lead_hash: carModel.currentLeadId,
7690	      part_name: part
7691	    };
7692
7693	    $.post(carModel.config.removedamageURL, params , function(data) {
7694	      // todo: loading
7695
7696	      if ( data.ok ) {
7697	        carModel.updatePart({ part: part }, 'destroy' );
7698	        carModel.updateView({ part: part }, 'destroy' );
7699	        carModel.config.modal.modal('hide');
7700	      } else {
7701	        console.error(data);
7702	        console.error('something went wrong');
7703	      }
7704	    });
7705	  },
7706
7707	  updatePart: function(damage, action) {
7708	    var $$part      = $('.'+damage.part);
7709
7710	    carModel.config.parts
7711	      .filter($$part)
7712	      .each(function() {
7713	        if (typeof action !== 'undefined' && action == 'destroy') {
7714	          $(this)
7715	            .removeData('damagetype').removeAttr('data-damagetype')
7716	            .removeData('damagedesc').removeAttr('data-damagedesc');
7717	        } else {
7718	          $(this).data({
7719	            'damagetype': damage.type,
7720	            'damagedesc': damage.desc
7721	          });
7722	        }
7723	      });
7724
7725	    carModel.formPopulate(damage.part);
7726	  },
7727
7728	  clearAllDamages: function () {
7729	    $.post(carModel.config.removeAllDamagesURL, {lead_hash: carModel.currentLeadId} , function(data) {
7730	      // todo: loading
7731	      if ( data.ok ) {
7732	        carModel.clearView();
7733	      } else {
7734	        console.error(data);
7735	        console.error('something went wrong');
7736	      }
7737	    });
7738	  },
7739
7740	  clearView: function () {
7741	    carModel.config.parts.each(function () {
7742	      var regExp = /damage.+?(?=\s|$)/gi;
7743
7744	      var _classList = this.className.baseVal;
7745	      _classList = _classList.replace(regExp, '');
7746
7747	      this.className.baseVal = _classList;
7748
7749	      $(this).removeData('damagetype').removeAttr('data-damagetype')
7750	             .removeData('damagedesc').removeAttr('data-damagedesc');
7751	    });
7752	  },
7753
7754	  updateView: function(damage, action) {
7755	    var $$part      = $('.'+damage.part),
7756	        _classList = [ carModel.config.partClass, damage.part ];
7757
7758	    if (typeof damage === 'undefined' || action != 'destroy') {
7759	      _classList.push(carModel.config.damagePrefix + damage.type);
7760	    }
7761
7762	    carModel.config.parts
7763	      .filter($$part)
7764	      .each(function() {
7765	        this.className.baseVal = _classList.join(' ');
7766	      });
7767	  }
7768	};
7769	$.fn.serializeObject = function() {
7770	  var o = {};
7771	  var a = this.serializeArray();
7772	  $.each(a, function() {
7773	    if (o[this.name] !== undefined) {
7774	      if (!o[this.name].push) {
7775	        o[this.name] = [o[this.name]];
7776	      }
7777	      o[this.name].push(this.value || '');
7778	    } else {
7779	      o[this.name] = this.value || '';
7780	    }
7781	  });
7782	  return o;
7783	};
7784
7785/***/ }),
7786
7787/***/ 321:
7788/***/ (function(module, exports) {
7789
7790	;(function($) {
7791	  $.fn.fullformTooltip = function (options) {
7792	    var $$this = $(this);
7793	    var tooltip = {
7794	      settings: {
7795	        container: 'body',
7796	        trigger: 'manual',
7797	        html: true,
7798	        placement: 'top',
7799	        content: 'blabla',
7800	        type: null
7801	      }
7802	    }
7803	    // allow overwrite of default settings
7804	    $.extend(tooltip.settings, options);
7805
7806	    if (tooltip.settings.type == 'image') {
7807	      tooltip.settings.content = function () {
7808	        return '<img src="'+$(this).attr('data-tooltip')+'" height="'+$(this).attr('data-tooltip-height')+'" width="'+$(this).attr('data-tooltip-width')+'">';
7809	      }
7810	    }
7811	    return this.popover(tooltip.settings);
7812	  };
7813
7814	  $(function() {
7815	    var tooltipVisible = null;
7816
7817	    $('.form-tooltip').show();
7818
7819	    $('[data-tooltip]').each(function () {
7820	      $(this)
7821	        .fullformTooltip({
7822	          type: $(this).attr('data-tooltip-type'),
7823	          content: $(this).attr('data-tooltip')
7824	        })
7825	        .on('click', function (e) {
7826	          //e.stopPropagation();
7827	        })
7828	    })
7829	    .on('show.bs.popover', function () {
7830	      tooltipVisible = this.id;
7831	      //console.log(tooltipVisible)
7832	    })
7833	    .on('hide.bs.popover', function () {
7834	      tooltipVisible = null;
7835	    })
7836	    .on('shown.bs.popover', function () {
7837	      var posTop = $('.popover').css('top');
7838	      $('.popover').css({
7839	        top: parseInt(posTop)- 18 + 'px'
7840	      })
7841	    })
7842
7843	    $('label[data-trigger="tooltip"]').on('click', function (e) {
7844	      var targetId = $(this).attr('for');
7845	      $('[data-tooltip]').not('#'+targetId).popover('hide');
7846	      $('#'+targetId).popover('show');
7847	      e.preventDefault();
7848	      e.stopPropagation();
7849	    });
7850
7851	    $(document).on('click', function(e) {
7852	      if (e.target != document.getElementById(tooltipVisible)) {
7853	        $('[data-tooltip]').popover('hide');
7854	      }
7855	    });
7856	  });
7857	})(jQuery);
7858
7859/***/ }),
7860
7861/***/ 322:
7862/***/ (function(module, exports, __webpack_require__) {
7863
7864	/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["reviewModule"] = __webpack_require__(323);
7865	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
7866
7867/***/ }),
7868
7869/***/ 323:
7870/***/ (function(module, exports) {
7871
7872	/**
7873	 * A module that controls the sticky behaviour of
7874	 * the sidebar in some pages.
7875	 * @module reviewModule
7876	 */
7877	var reviewModule = module.exports = (function () {
7878	  var pageContainer, topOffset;
7879	  var padding = 9;
7880
7881	  var $aside = $('aside');
7882	  var $main  = $('main');
7883	  var $asideContent = $('.aside-content');
7884	  var $window = $(window);
7885
7886	  /**
7887	   * Returns an integer value without the px unit
7888	   * @param {String} px string representation of quantity in px unit (e.g. '10px')
7889	   */
7890	  function pxToInt(px) {
7891	    var unitlessString = px.replace('px', '');
7892	    return parseInt(unitlessString);
7893	  }
7894
7895	  /**
7896	   * Returns the left offset that should be used for calculations
7897	   */
7898	  function getLeftOffset() {
7899	    return pxToInt($aside.css('padding-left')) + pxToInt($main.css('padding-right'));
7900	  }
7901
7902	  /**
7903	   * Returns the top offset that should be used for calculations
7904	   */
7905	  function getTopOffset() {
7906	    return topOffset || 0;
7907	  }
7908
7909	  /**
7910	   * Checks if the the window width is equal or
7911	   * larger than the breakpoint
7912	   * @param {Number} breakpoint
7913	   * @returns {Boolean}
7914	   */
7915	  function isOnBreakpoint(breakpoint) {
7916	    return $window.width() >= breakpoint;
7917	  }
7918
7919	  /**
7920	   * Sets the style attribute of the element to empty string
7921	   * @param {Object} element jQuery object
7922	   */
7923	  function removeStyle(element) {
7924	    element.attr('style', '');
7925	  }
7926
7927	  /**
7928	   * Sets the css properties of the aside element in such a way
7929	   * that its position is absolute
7930	   * @param {Number} left
7931	   * @param {Number} top
7932	   */
7933	  function setAsideAbsolute(left, top) {
7934	    $aside.css({
7935	      left: left,
7936	      position: 'absolute',
7937	      top: top,
7938	      width: $aside.css('width'),
7939	      'z-index': 1
7940	    });
7941	  }
7942
7943	  /**
7944	   * Unset the sticky behaviour of the aside element
7945	   * @param {Boolean} shouldPositionAbsolute Whether to set the sidebar position to absolute or not
7946	   * @param {Number} top Top offset, absolute position only
7947	   */
7948	  function unfixAside(shouldPositionAbsolute, top) {
7949	    if (shouldPositionAbsolute) {
7950	      var left = $main.width() + getLeftOffset();
7951
7952	      setAsideAbsolute(left, top);
7953	    } else {
7954	      removeStyle($aside);
7955	    }
7956
7957	    removeStyle($asideContent);
7958	  }
7959
7960	  /**
7961	   * Set aside element positioned at the bottom of the page container
7962	   */
7963	  function fixAsideToTheBottom(shouldPositionAbsolute, absolutePositionTop) {
7964	    var left = shouldPositionAbsolute ? $main.width() + getLeftOffset() : 'auto';
7965	    var top = pageContainer.outerHeight() - $aside.outerHeight() - getTopOffset() + pageContainer.offset().top - padding;
7966	    top = shouldPositionAbsolute ? top - absolutePositionTop - padding*2 : top;
7967
7968	    removeStyle($aside);
7969	    setAsideAbsolute(left, top);
7970	  }
7971
7972	  /**
7973	   * Set the sticky behaviour of the aside element
7974	   */
7975	  function fixAside(shouldPositionAbsolute) {
7976	    $asideContent.css({ 'margin-top': $aside.height() });
7977	    $aside.css({
7978	      left: shouldPositionAbsolute? $main.offset().left + $main.width() + getLeftOffset() : $aside.offset().left,
7979	      position: 'fixed',
7980	      top: padding,
7981	      width: $aside.css('width')
7982	    });
7983	  }
7984
7985	  /**
7986	   * Set or unset the sticky behaviour of the aside element based on the params
7987	   * and the amount of scrolled pixels
7988	   * @param {Number} windowBreakPoint Sets the limit below which the sidebar is not
7989	   * @param {Boolean} shouldPositionAbsolute Whether to set the sidebar position to absolute or not
7990	   * @param {Number} top Top offset, absolute position only
7991	   */
7992	  function updateAside(windowBreakPoint, shouldPositionAbsolute, top) {
7993	    var scrolled = $(document).scrollTop();
7994	    var shouldBeFixed = shouldPositionAbsolute ? scrolled > (getTopOffset() + pageContainer.offset().top) : scrolled > getTopOffset();
7995	    var bottomBreakpoint = pageContainer.offset().top + pageContainer.outerHeight() - $aside.outerHeight();
7996	    bottomBreakpoint = shouldPositionAbsolute ? bottomBreakpoint - top - padding*2 : bottomBreakpoint;
7997	    var shouldBeFixedToBottom = scrolled > bottomBreakpoint;
7998
7999	    $aside.css({ 'z-index': 1000 });
8000
8001	    // If window is big enough to show the sidebar at the right
8002	    if (isOnBreakpoint(windowBreakPoint)) {
8003	      // If already scrolled past the top of the container
8004	      if (shouldBeFixed) {
8005	        // if reached the bottom limit
8006	        if (shouldBeFixedToBottom) {
8007	          fixAsideToTheBottom(shouldPositionAbsolute, top);
8008	          // Otherwise (there's still more to scroll)
8009	        } else {
8010	          fixAside(shouldPositionAbsolute);
8011	        }
8012	      // Otherwise (scrolled above the top of the sidebar)
8013	      } else {
8014	        unfixAside(shouldPositionAbsolute, top);
8015	        $('#scrollspy-nav ul li:first-child').addClass('active');
8016	      }
8017	    // Otherwise (window is not big enough)
8018	    } else {
8019	      unfixAside(false, top);
8020	    }
8021	  };
8022
8023	  /** TODO: document this function in a clearer way
8024	   * Function for moving form after comment index
8025	   * @param {*} commentIndex
8026	   */
8027	  function conversionFormInit(commentIndex) {
8028	    $('.car-form-smaller')
8029	      .removeClass('hide')
8030	      .insertAfter(
8031	        $('.panel-customer-comment').eq(commentIndex)
8032	      );
8033	  };
8034
8035	  /**
8036	   * Initialize the sticky behavior for the aside element
8037	   * @param {Number} windowBreakPoint Sets the limit below which the sidebar is not
8038	   * @param {Boolean} shouldPositionAbsolute Whether to set the sidebar position to absolute or not
8039	   * @param {Number} top Top offset, absolute position only
8040	   */
8041	  function initSidebar(windowBreakPoint, shouldPositionAbsolute, top) {
8042	    // Store the offset now and forever
8043	    topOffset = shouldPositionAbsolute ? $aside.offset().top - pageContainer.offset().top : $aside.offset().top;
8044	    leftOffset = $aside.offset().left;
8045
8046	    // bind updateAside with params
8047	    var boundUpdateAside = updateAside.bind(null, windowBreakPoint, shouldPositionAbsolute, top);
8048
8049	    // Set listeners for scroll and resize events
8050	    $window.scroll(boundUpdateAside);
8051	    $window.resize(boundUpdateAside);
8052
8053	    // call once
8054	    boundUpdateAside();
8055	  }
8056
8057	  /**
8058	   * Set the selector to position container form.
8059	   * @param {String} containerSelector
8060	   * @param {Number} windowBreakPoint
8061	   * @param {Object}
8061 [cfg] Sticky nav config
8062	   * @param {Boolean} [cfg.shouldPositionAbsolute]
8063	   * @param {String} [cfg.mainContainerSelector]
8064	   * @param {Number} [cfg.top] Top offset, absolute position only
8065	   */
8066	  function setForm(containerSelector, windowBreakPoint, cfg) {
8067	    // store the container of the page
8068	    cfg = cfg || {};
8069	    pageContainer = $(containerSelector);
8070	    var mainContainerSelector = cfg.mainContainerSelector || 'main';
8071	    $main = $(mainContainerSelector);
8072
8073	    var boundInitSidebar = initSidebar.bind(null, windowBreakPoint, cfg.shouldPositionAbsolute, cfg.top);
8074
8075	    // If view is big enough start the sidebar logic
8076	    if (isOnBreakpoint(windowBreakPoint)) {
8077	      boundInitSidebar();
8078	    } else { // Otherwise, wait until screen is resized to big enough size
8079	      $(window).on('resize', onWindowResize);
8080	    }
8081
8082	    function onWindowResize() {
8083	      if (isOnBreakpoint(windowBreakPoint)) {
8084	        boundInitSidebar();
8085	        // then remove the initial resize listener
8086	        $window.off('resize', onWindowResize);
8087	      }
8088	    }
8089
8090	    // return the container to allow chaining
8091	    return pageContainer;
8092	  }
8093
8094	  return {
8095	    setForm: setForm,
8096	    conversionFormInit: conversionFormInit,
8097	  };
8098	})();
8099
8100
8101/***/ }),
8102
8103/***/ 324:
8104/***/ (function(module, exports, __webpack_require__) {
8105
8106	/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["riskFreeSummary"] = __webpack_require__(325);
8107	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
8108
8109/***/ }),
8110
8111/***/ 325:
8112/***/ (function(module, exports) {
8113
8114	var riskFreeSummary = (module.exports = (function() {
8115	  return function() {
8116	    $.post(
8117	      "/lp/_service/branchDays/",
8118	      {
8119	        hash: $("#carHash").val(),
8120	        branch: $("#branches").val()
8121	      },
8122	      function(days) {
8123	        var html = days
8124	          .map(function(day) {
8125	            return '<option value="' + day.id + '">' + day.label + "</option>";
8126	          })
8127	          .join("");
8128
8129	        $("#days").append(html);
8130	      }
8131	    );
8132	  };
8133	})());
8134
8135
8136/***/ }),
8137
8138/***/ 326:
8139/***/ (function(module, exports, __webpack_require__) {
8140
8141	window.stickyWidget = (function initSticky(window) {
8142	  return {
8143	    init: init
8144	  };
8145
8146	  function init(sidebarSelector, _options) {
8147	    var ResizeSensor = __webpack_require__(327);
8148	    window.ResizeSensor = ResizeSensor;
8149	    var StickySidebar = __webpack_require__(328).default;
8150
8151	    var defaults = {
8152	      topSpacing: 5,
8153	      bottomSpacing: 0,
8154	      containerSelector: '.js-sticky-main-container',
8155	      innerWrapperSelector: '.js-sticky-widget',
8156	      minWidth: 1026,
8157	      resizeSensor: true
8158	    };
8159
8160	    if (_options) {
8161	      for (var attrname in _options) { defaults[attrname] = _options[attrname]; }
8162	    }
8163
8164	    var options = defaults;
8165	    var sidebarSelector = sidebarSelector || '.js-sticky-sidebar';
8166	    var containerSelector = options.containerSelector;
8167	    var innerWrapperSelector = options.innerWrapperSelector;
8168	    var belowContent = document.querySelector('.js-below-content');
8169	    var stickySidebar = document.querySelector(sidebarSelector);
8170	    var stickyElement = document.querySelector(innerWrapperSelector);
8171	    var stickyContentContainer = document.querySelector(containerSelector);
8172
8173	    var instance = new StickySidebar(stickySidebar, {
8174	      topSpacing: 5,
8175	      bottomSpacing: 0,
8176	      containerSelector: containerSelector,
8177	      innerWrapperSelector: innerWrapperSelector,
8178	      minWidth: 1026,
8179	      resizeSensor: true
8180	    });
8181
8182
8183	    new ResizeSensor(stickyElement, function() {
8184	        setTimeout(function updateStickyTimeout(){
8185	          instance.updateSticky();
8186	        }, 0);
8187	    });
8188
8189	    stickySidebar.addEventListener("affix.breakpoint.stickySidebar", function() {
8190	      var sib = belowContent || stickyElement.nextElementSibling;
8191	      if(sib) {
8192	        removeClass(sib, 'sibbling-affixed');
8193	        sib.style.marginTop = 'auto';
8194	      }
8195	    });
8196
8197	    stickySidebar.addEventListener("affix.top.stickySidebar", function() {
8198	      var sib = belowContent || stickyElement.nextElementSibling;
8199	      var height = outerHeight(stickyElement);
8200	      var isAffixed = hasClass(stickySidebar, 'is-affixed');
8201	      if(sib && !isAffixed) {
8202	        sib.style.marginTop = height + 'px';
8203	        addClass(sib, 'sibbling-affixed');
8204	      }
8205	    });
8206
8207	    stickySidebar.addEventListener("affixed.static.stickySidebar", function() {
8208	      var sib = belowContent || stickyElement.nextElementSibling;
8209	      if(sib) {
8210	        sib.style.marginTop = 'auto';
8211	        removeClass(sib, 'sibbling-affixed');
8212	      }
8213	      setTimeout(function() {
8214	        instance.calcDimensions();
8215	      }, 0)
8216	    });
8217	  }
8218
8219	  function hasClass(el, className) {
8220	    if (el.classList){
8221	      return el.classList.contains(className);
8222	    } else {
8223	      return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
8224	    }
8225	  }
8226
8227	  function addClass(el, className) {
8228	    if (el.classList) {
8229	      el.classList.add(className);
8230	    } else {
8231	      el.className += ' ' + className;
8232	    }
8233	  }
8234
8235	  function removeClass(el, className) {
8236	    if (el.classList) {
8237	      el.classList.remove(className);
8238	    } else {
8239	      el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
8240	    }
8241	  }
8242
8243	  function outerHeight(el) {
8244	    var height = el.offsetHeight;
8245	    var style = getComputedStyle(el);
8246	    height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);
8247	    return height;
8248	  }
8249	})(window);
8250
8251
8252/***/ }),
8253
8254/***/ 327:
8255/***/ (function(module, exports, __webpack_require__) {
8256
8257	var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;'use strict';
8258
8259	/**
8260	 * Copyright Marc J. Schmidt. See the LICENSE file at the top-level
8261	 * directory of this distribution and at
8262	 * https://github.com/marcj/css-element-queries/blob/master/LICENSE.
8263	 */
8264	(function (root, factory) {
8265	    if (true) {
8266	        !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
8267	    } else if (typeof exports === "object") {
8268	        module.exports = factory();
8269	    } else {
8270	        root.ResizeSensor = factory();
8271	    }
8272	}(typeof window !== 'undefined' ? window : this, function () {
8273
8274	    // Make sure it does not throw in a SSR (Server Side Rendering) situation
8275	    if (typeof window === "undefined") {
8276	        return null;
8277	    }
8278	    // https://github.com/Semantic-Org/Semantic-UI/issues/3855
8279	    // https://github.com/marcj/css-element-queries/issues/257
8280	    var globalWindow = typeof window != 'undefined' && window.Math == Math
8281	        ? window
8282	        : typeof self != 'undefined' && self.Math == Math
8283	            ? self
8284	            : Function('return this')();
8285	    // Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor.
8286	    // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and
8287	    // would generate too many unnecessary events.
8288	    var requestAnimationFrame = globalWindow.requestAnimationFrame ||
8289	        globalWindow.mozRequestAnimationFrame ||
8290	        globalWindow.webkitRequestAnimationFrame ||
8291	        function (fn) {
8292	            return globalWindow.setTimeout(fn, 20);
8293	        };
8294
8295	    /**
8296	     * Iterate over each of the provided element(s).
8297	     *
8298	     * @param {HTMLElement|HTMLElement[]} elements
8299	     * @param {Function}                  callback
8300	     */
8301	    function forEachElement(elements, callback){
8302	        var elementsType = Object.prototype.toString.call(elements);
8303	        var isCollectionTyped = ('[object Array]' === elementsType
8304	            || ('[object NodeList]' === elementsType)
8305	            || ('[object HTMLCollection]' === elementsType)
8306	            || ('[object Object]' === elementsType)
8307	            || ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery
8308	            || ('undefined' !== typeof Elements && elements instanceof Elements) //mootools
8309	        );
8310	        var i = 0, j = elements.length;
8311	        if (isCollectionTyped) {
8312	            for (; i < j; i++) {
8313	                callback(elements[i]);
8314	            }
8315	        } else {
8316	            callback(elements);
8317	        }
8318	    }
8319
8320	    /**
8321	    * Get element size
8322	    * @param {HTMLElement} element
8323	    * @returns {Object} {width, height}
8324	    */
8325	    function getElementSize(element) {
8326	        if (!element.getBoundingClientRect) {
8327	            return {
8328	                width: element.offsetWidth,
8329	                height: element.offsetHeight
8330	            }
8331	        }
8332
8333	        var rect = element.getBoundingClientRect();
8334	        return {
8335	            width: Math.round(rect.width),
8336	            height: Math.round(rect.height)
8337	        }
8338	    }
8339
8340	    /**
8341	     * Apply CSS styles to element.
8342	     *
8343	     * @param {HTMLElement} element
8344	     * @param {Object} style
8345	     */
8346	    function setStyle(element, style) {
8347	        Object.keys(style).forEach(function(key) {
8348	            element.style[key] = style[key];
8349	        });
8350	    }
8351
8352	    /**
8353	     * Class for dimension change detection.
8354	     *
8355	     * @param {Element|Element[]|Elements|jQuery} element
8356	     * @param {Function} callback
8357	     *
8358	     * @constructor
8359	     */
8360	    var ResizeSensor = function(element, callback) {
8361	        /**
8362	         *
8363	         * @constructor
8364	         */
8365	        function EventQueue() {
8366	            var q = [];
8367	            this.add = function(ev) {
8368	                q.push(ev);
8369	            };
8370
8371	            var i, j;
8372	            this.call = function(sizeInfo) {
8373	                for (i = 0, j = q.length; i < j; i++) {
8374	                    q[i].call(this, sizeInfo);
8375	                }
8376	            };
8377
8378	            this.remove = function(ev) {
8379	                var newQueue = [];
8380	                for(i = 0, j = q.length; i < j; i++) {
8381	                    if(q[i] !== ev) newQueue.push(q[i]);
8382	                }
8383	                q = newQueue;
8384	            };
8385
8386	            this.length = function() {
8387	                return q.length;
8388	            }
8389	        }
8390
8391	        /**
8392	         *
8393	         * @param {HTMLElement} element
8394	         * @param {Function}    resized
8395	         */
8396	        function attachResizeEvent(element, resized) {
8397	            if (!element) return;
8398	            if (element.resizedAttached) {
8399	                element.resizedAttached.add(resized);
8400	                return;
8401	            }
8402
8403	            element.resizedAttached = new EventQueue();
8404	            element.resizedAttached.add(resized);
8405
8406	            element.resizeSensor = document.createElement('div');
8407	            element.resizeSensor.dir = 'ltr';
8408	            element.resizeSensor.className = 'resize-sensor';
8409
8410	            var style = {
8411	                pointerEvents: 'none',
8412	                position: 'absolute',
8413	                left: '0px',
8414	                top: '0px',
8415	                right: '0px',
8416	                bottom: '0px',
8417	                overflow: 'hidden',
8418	                zIndex: '-1',
8419	                visibility: 'hidden',
8420	                maxWidth: '100%'
8421	            };
8422	            var styleChild = {
8423	                position: 'absolute',
8424	                left: '0px',
8425	                top: '0px',
8426	                transition: '0s',
8427	            };
8428
8429	            setStyle(element.resizeSensor, style);
8430
8431	            var expand = document.createElement('div');
8432	            expand.className = 'resize-sensor-expand';
8433	            setStyle(expand, style);
8434
8435	            var expandChild = document.createElement('div');
8436	            setStyle(expandChild, styleChild);
8437	            expand.appendChild(expandChild);
8438
8439	            var shrink = document.createElement('div');
8440	            shrink.className = 'resize-sensor-shrink';
8441	            setStyle(shrink, style);
8442
8443	            var shrinkChild = document.createElement('div');
8444	            setStyle(shrinkChild, styleChild);
8445	            setStyle(shrinkChild, { width: '200%', height: '200%' });
8446	            shrink.appendChild(shrinkChild);
8447
8448	            element.resizeSensor.appendChild(expand);
8449	            element.resizeSensor.appendChild(shrink);
8450	            element.appendChild(element.resizeSensor);
8451
8452	            var computedStyle = window.getComputedStyle(element);
8453	            var position = computedStyle ? computedStyle.getPropertyValue('position') : null;
8454	            if ('absolute' !== position && 'relative' !== position && 'fixed' !== position) {
8455	                element.style.position = 'relative';
8456	            }
8457
8458	            var dirty, rafId;
8459	            var size = getElementSize(element);
8460	            var lastWidth = 0;
8461	            var lastHeight = 0;
8462	            var initialHiddenCheck = true;
8463	            var lastAnimationFrame = 0;
8464
8465	            var resetExpandShrink = function () {
8466	                var width = element.offsetWidth;
8467	                var height = element.offsetHeight;
8468
8469	                expandChild.style.width = (width + 10) + 'px';
8470	                expandChild.style.height = (height + 10) + 'px';
8471
8472	                expand.scrollLeft = width + 10;
8473	                expand.scrollTop = height + 10;
8474
8475	                shrink.scrollLeft = width + 10;
8476	                shrink.scrollTop = height + 10;
8477	            };
8478
8479	            var reset = function() {
8480	                // Check if element is hidden
8481	                if (initialHiddenCheck) {
8482	                    var invisible = element.offsetWidth === 0 && element.offsetHeight === 0;
8483	                    if (invisible) {
8484	                        // Check in next frame
8485	                        if (!lastAnimationFrame){
8486	                            lastAnimationFrame = requestAnimationFrame(function(){
8487	                                lastAnimationFrame = 0;
8488
8489	                                reset();
8490	                            });
8491	                        }
8492
8493	                        return;
8494	                    } else {
8495	                        // Stop checking
8496	                        initialHiddenCheck = false;
8497	                    }
8498	                }
8499
8500	                resetExpandShrink();
8501	            };
8502	            element.resizeSensor.resetSensor = reset;
8503
8504	            var onResized = function() {
8505	                rafId = 0;
8506
8507	                if (!dirty) return;
8508
8509	                lastWidth = size.width;
8510	                lastHeight = size.height;
8511
8512	                if (element.resizedAttached) {
8513	                    element.resizedAttached.call(size);
8514	                }
8515	            };
8516
8517	            var onScroll = function() {
8518	                size = getElementSize(element);
8519	                dirty = size.width !== lastWidth || size.height !== lastHeight;
8520
8521	                if (dirty && !rafId) {
8522	                    rafId = requestAnimationFrame(onResized);
8523	                }
8524
8525	                reset();
8526	            };
8527
8528	            var addEvent = function(el, name, cb) {
8529	                if (el.attachEvent) {
8530	                    el.attachEvent('on' + name, cb);
8531	                } else {
8532	                    el.addEventListener(name, cb);
8533	                }
8534	            };
8535
8536	            addEvent(expand, 'scroll', onScroll);
8537	            addEvent(shrink, 'scroll', onScroll);
8538
8539	            // Fix for custom Elements
8540	            requestAnimationFrame(reset);
8541	        }
8542
8543	        forEachElement(element, function(elem){
8544	            attachResizeEvent(elem, callback);
8545	        });
8546
8547	        this.detach = function(ev) {
8548	            ResizeSensor.detach(element, ev);
8549	        };
8550
8551	        this.reset = function() {
8552	            element.resizeSensor.resetSensor();
8553	        };
8554	    };
8555
8556	    ResizeSensor.reset = function(element) {
8557	        forEachElement(element, function(elem){
8558	            elem.resizeSensor.resetSensor();
8559	        });
8560	    };
8561
8562	    ResizeSensor.detach = function(element, ev) {
8563	        forEachElement(element, function(elem){
8564	            if (!elem) return;
8565	            if(elem.resizedAttached && typeof ev === "function"){
8566	                elem.resizedAttached.remove(ev);
8567	                if(elem.resizedAttached.length()) return;
8568	            }
8569	            if (elem.resizeSensor) {
8570	                if (elem.contains(elem.resizeSensor)) {
8571	                    elem.removeChild(elem.resizeSensor);
8572	                }
8573	                delete elem.resizeSensor;
8574	                delete elem.resizedAttached;
8575	            }
8576	        });
8577	    };
8578
8579	    if (typeof MutationObserver !== "undefined") {
8580	        var observer = new MutationObserver(function (mutations) {
8581	            for (var i in mutations) {
8582	                if (mutations.hasOwnProperty(i)) {
8583	                    var items = mutations[i].addedNodes;
8584	                    for (var j = 0; j < items.length; j++) {
8585	                        if (items[j].resizeSensor) {
8586	                            ResizeSensor.reset(items[j]);
8587	                        }
8588	                    }
8589	                }
8590	            }
8591	        });
8592
8593	        document.addEventListener("DOMContentLoaded", function (event) {
8594	            observer.observe(document.body, {
8595	                childList: true,
8596	                subtree: true,
8597	            });
8598	        });
8599	    }
8600
8601	    return ResizeSensor;
8602
8603	}));
8604
8605/***/ }),
8606
8607/***/ 328:
8608/***/ (function(module, exports, __webpack_require__) {
8609
8610	/* WEBPACK VAR INJECTION */(function(global) {(function (global, factory) {
8611		 true ? factory(exports) :
8612		typeof define === 'function' && define.amd ? define(['exports'], factory) :
8613		(factory((global.StickySidebar = {})));
8614	}(this, (function (exports) { 'use strict';
8615
8616	var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
8617
8618
8619
8620	function unwrapExports (x) {
8621		return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
8622	}
8623
8624	function createCommonjsModule(fn, module) {
8625		return module = { exports: {} }, fn(module, module.exports), module.exports;
8626	}
8627
8628	var stickySidebar = createCommonjsModule(function (module, exports) {
8629	(function (global, factory) {
8630	  if (false) {
8631	    undefined(['exports'], factory);
8632	  } else {
8633	    factory(exports);
8634	  }
8635	})(commonjsGlobal, function (exports) {
8636	  Object.defineProperty(exports, "__esModule", {
8637	    value: true
8638	  });
8639
8640	  function _classCallCheck(instance, Constructor) {
8641	    if (!(instance instanceof Constructor)) {
8642	      throw new TypeError("Cannot call a class as a function");
8643	    }
8644	  }
8645
8646	  var _createClass = function () {
8647	    function defineProperties(target, props) {
8648	      for (var i = 0; i < props.length; i++) {
8649	        var descriptor = props[i];
8650	        descriptor.enumerable = descriptor.enumerable || false;
8651	        descriptor.configurable = true;
8652	        if ("value" in descriptor) descriptor.writable = true;
8653	        Object.defineProperty(target, descriptor.key, descriptor);
8654	      }
8655	    }
8656
8657	    return function (Constructor, protoProps, staticProps) {
8658	      if (protoProps) defineProperties(Constructor.prototype, protoProps);
8659	      if (staticProps) defineProperties(Constructor, staticProps);
8660	      return Constructor;
8661	    };
8662	  }();
8663
8664	  /**
8665	   * Sticky Sidebar JavaScript Plugin.
8666	   * @version 3.3.4
8667	   * @author Ahmed Bouhuolia <[email protected]>
8668	   * @license The MIT License (MIT)
8669	   */
8670	  var StickySidebar = function () {
8671
8672	    // ---------------------------------
vendor: 3,490 bytes, lines 8673-8794
8673	    // # Define Constants
8674	    // ---------------------------------
8675	    //
8676	    var EVENT_KEY = '.stickySidebar';
8677	    var DEFAULTS = {
8678	      /**
8679	       * Additional top spacing of the element when it becomes sticky.
8680	       * @type {Numeric|Function}
8681	       */
8682	      topSpacing: 0,
8683
8684	      /**
8685	       * Additional bottom spacing of the element when it becomes sticky.
8686	       * @type {Numeric|Function}
8687	       */
8688	      bottomSpacing: 0,
8689
8690	      /**
8691	       * Container sidebar selector to know what the beginning and end of sticky element.
8692	       * @type {String|False}
8693	       */
8694	      containerSelector: false,
8695
8696	      /**
8697	       * Inner wrapper selector.
8698	       * @type {String}
8699	       */
8700	      innerWrapperSelector: '.inner-wrapper-sticky',
8701
8702	      /**
8703	       * The name of CSS class to apply to elements when they have become stuck.
8704	       * @type {String|False}
8705	       */
8706	      stickyClass: 'is-affixed',
8707
8708	      /**
8709	       * Detect when sidebar and its container change height so re-calculate their dimensions.
8710	       * @type {Boolean}
8711	       */
8712	      resizeSensor: true,
8713
8714	      /**
8715	       * The sidebar returns to its normal position if its width below this value.
8716	       * @type {Numeric}
8717	       */
8718	      minWidth: false,
8719
8720	      withTransForms: false
8721	    };
8722
8723	    // ---------------------------------
8724	    // # Class Definition
8725	    // ---------------------------------
8726	    //
8727	    /**
8728	     * Sticky Sidebar Class.
8729	     * @public
8730	     */
8731
8732	    var StickySidebar = function () {
8733
8734	      /**
8735	       * Sticky Sidebar Constructor.
8736	       * @constructor
8737	       * @param {HTMLElement|String} sidebar - The sidebar element or sidebar selector.
8738	       * @param {Object} options - The options of sticky sidebar.
8739	       */
8740	      function StickySidebar(sidebar) {
8741	        var _this = this;
8742
8743	        var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
8744
8745	        _classCallCheck(this, StickySidebar);
8746
8747	        this.options = StickySidebar.extend(DEFAULTS, options);
8748
8749	        // Sidebar element query if there's no one, throw error.
8750	        this.sidebar = 'string' === typeof sidebar ? document.querySelector(sidebar) : sidebar;
8751	        if ('undefined' === typeof this.sidebar) throw new Error("There is no specific sidebar element.");
8752
8753	        this.sidebarInner = false;
8754	        this.container = this.sidebar.parentElement;
8755
8756	        // Current Affix Type of sidebar element.
8757	        this.affixedType = 'STATIC';
8758	        this.direction = 'down';
8759	        this.support = {
8760	          transform: false,
8761	          transform3d: false
8762	        };
8763
8764	        this._initialized = false;
8765	        this._reStyle = false;
8766	        this._breakpoint = false;
8767
8768	        // Dimensions of sidebar, container and screen viewport.
8769	        this.dimensions = {
8770	          translateY: 0,
8771	          maxTranslateY: 0,
8772	          topSpacing: 0,
8773	          lastTopSpacing: 0,
8774	          bottomSpacing: 0,
8775	          lastBottomSpacing: 0,
8776	          sidebarHeight: 0,
8777	          sidebarWidth: 0,
8778	          containerTop: 0,
8779	          containerHeight: 0,
8780	          viewportHeight: 0,
8781	          viewportTop: 0,
8782	          lastViewportTop: 0
8783	        };
8784
8785	        // Bind event handlers for referencability.
8786	        ['handleEvent'].forEach(function (method) {
8787	          _this[method] = _this[method].bind(_this);
8788	        });
8789
8790	        // Initialize sticky sidebar for first time.
8791	        this.initialize();
8792	      }
8793
8794	      /**
8795	       * Initializes the sticky sidebar by adding inner wrapper, define its container,
8796	       * min-width breakpoint, calculating dimensions, adding helper classes and inline style.
8797	       * @private
8798	       */
8799
8800
8801	      _createClass(StickySidebar, [{
8802	        key: 'initialize',
8803	        value: function initialize() {
8804	          var _this2 = this;
8805
8806	          this._setSupportFeatures();
8807
8808	          // Get sticky sidebar inner wrapper, if not found, will create one.
8809	          if (this.options.innerWrapperSelector) {
8810	            this.sidebarInner = this.sidebar.querySelector(this.options.innerWrapperSelector);
8811
8812	            if (null === this.sidebarInner) this.sidebarInner = false;
8813	          }
8814
8815	          if (!this.sidebarInner) {
8816	            var wrapper = document.createElement('div');
8817	            wrapper.setAttribute('class', 'inner-wrapper-sticky');
8818	            this.sidebar.appendChild(wrapper);
8819
8820	            while (this.sidebar.firstChild != wrapper) {
8821	              wrapper.appendChild(this.sidebar.firstChild);
8822	            }this.sidebarInner = this.sidebar.querySelector('.inner-wrapper-sticky');
8823	          }
8824
8825	          // Container wrapper of the sidebar.
8826	          if (this.options.containerSelector) {
8827	            var containers = document.querySelectorAll(this.options.containerSelector);
8828	            containers = Array.prototype.slice.call(containers);
8829
8830	            containers.forEach(function (container, item) {
8831	              if (!container.contains(_this2.sidebar)) return;
8832	              _this2.container = container;
8833	            });
8834
8835	            if (!containers.length) throw new Error("The container does not contains on the sidebar.");
8836	          }
8837
8838	          // If top/bottom spacing is not function parse value to integer.
8839	          if ('function' !== typeof this.options.topSpacing) this.options.topSpacing = parseInt(this.options.topSpacing) || 0;
8840
8841	          if ('function' !== typeof this.options.bottomSpacing) this.options.bottomSpacing = parseInt(this.options.bottomSpacing) || 0;
8842
8843	          // Breakdown sticky sidebar if screen width below `options.minWidth`.
8844	          this._widthBreakpoint();
8845
8846	          // Calculate dimensions of sidebar, container and viewport.
8847	          this.calcDimensions();
8848
8849	          // Affix sidebar in proper position.
8850	          this.stickyPosition();
8851
8852	          // Bind all events.
8853	          this.bindEvents();
8854
8855	          // Inform other properties the sticky sidebar is initialized.
8856	          this._initialized = true;
8857	        }
8858	      }, {
8859	        key: 'bindEvents',
8860	        value: function bindEvents() {
8861	          window.addEventListener('resize', this, { passive: true, capture: false });
8862	          window.addEventListener('scroll', this, { passive: true, capture: false });
8863
8864	          this.sidebar.addEventListener('update' + EVENT_KEY, this);
8865
8866	          if (this.options.resizeSensor && 'undefined' !== typeof ResizeSensor) {
8867	            new ResizeSensor(this.sidebarInner, this.handleEvent);
8868	            new ResizeSensor(this.container, this.handleEvent);
8869	          }
8870	        }
8871	      }, {
8872	        key: 'handleEvent',
8873	        value: function handleEvent(event) {
8874	          this.updateSticky(event);
8875	        }
8876	      }, {
8877	        key: 'calcDimensions',
8878	        value: function calcDimensions() {
8879	          if (this._breakpoint) return;
8880	          var dims = this.dimensions;
8881
8882	          // Container of sticky sidebar dimensions.
8883	          dims.containerTop = StickySidebar.offsetRelative(this.container).top;
8884	          dims.containerHeight = this.container.clientHeight;
8885	          dims.containerBottom = dims.containerTop + dims.containerHeight;
8886
8887	          // Sidebar dimensions.
8888	          dims.sidebarHeight = this.sidebarInner.offsetHeight;
8889	          dims.sidebarWidth = this.sidebarInner.offsetWidth;
8890
8891	          // Screen viewport dimensions.
8892	          dims.viewportHeight = window.innerHeight;
8893
8894	          // Maximum sidebar translate Y.
8895	          dims.maxTranslateY = dims.containerHeight - dims.sidebarHeight;
8896
8897	          this._calcDimensionsWithScroll();
8898	        }
8899	      }, {
8900	        key: '_calcDimensionsWithScroll',
8901	        value: function _calcDimensionsWithScroll() {
8902	          var dims = this.dimensions;
8903	          var horizontalSpacing = parseInt(getComputedStyle(this.sidebar).paddingLeft || 0, 10);
8904	          dims.sidebarLeft = StickySidebar.offsetRelative(this.sidebar).left + horizontalSpacing;
8905
8906	          dims.viewportTop = document.documentElement.scrollTop || document.body.scrollTop;
8907	          dims.viewportBottom = dims.viewportTop + dims.viewportHeight;
8908	          dims.viewportLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
8909
8910	          dims.topSpacing = this.options.topSpacing;
8911	          dims.bottomSpacing = this.options.bottomSpacing;
8912
8913	          if ('function' === typeof dims.topSpacing) dims.topSpacing = parseInt(dims.topSpacing(this.sidebar)) || 0;
8914
8915	          if ('function' === typeof dims.bottomSpacing) dims.bottomSpacing = parseInt(dims.bottomSpacing(this.sidebar)) || 0;
8916
8917	          if ('VIEWPORT-TOP' === this.affixedType) {
8918	            // Adjust translate Y in the case decrease top spacing value.
8919	            if (dims.topSpacing < dims.lastTopSpacing) {
8920	              dims.translateY += dims.lastTopSpacing - dims.topSpacing;
8921	              this._reStyle = true;
8922	            }
8923	          } else if ('VIEWPORT-BOTTOM' === this.affixedType) {
8924	            // Adjust translate Y in the case decrease bottom spacing value.
8925	            if (dims.bottomSpacing < dims.lastBottomSpacing) {
8926	              dims.translateY += dims.lastBottomSpacing - dims.bottomSpacing;
8927	              this._reStyle = true;
8928	            }
8929	          }
8930
8931	          dims.lastTopSpacing = dims.topSpacing;
8932	          dims.lastBottomSpacing = dims.bottomSpacing;
8933	        }
8934	      }, {
8935	        key: 'isSidebarFitsViewport',
8936	        value: function isSidebarFitsViewport() {
8937	          var dims = this.dimensions;
8938	          var offset = this.scrollDirection === 'down' ? dims.lastBottomSpacing : dims.lastTopSpacing;
8939	          return this.dimensions.sidebarHeight + offset < this.dimensions.viewportHeight;
8940	        }
8941	      }, {
8942	        key: 'observeScrollDir',
8943	        value: function observeScrollDir() {
8944	          var dims = this.dimensions;
8945	          if (dims.lastViewportTop === dims.viewportTop) return;
8946
8947	          var furthest = 'down' === this.direction ? Math.min : Math.max;
8948
8949	          // If the browser is scrolling not in the same direction.
vendor: 5,617 bytes, lines 8950-9080
8950	          if (dims.viewportTop === furthest(dims.viewportTop, dims.lastViewportTop)) this.direction = 'down' === this.direction ? 'up' : 'down';
8951	        }
8952	      }, {
8953	        key: 'getAffixType',
8954	        value: function getAffixType() {
8955	          this._calcDimensionsWithScroll();
8956	          var dims = this.dimensions;
8957	          var colliderTop = dims.viewportTop + dims.topSpacing;
8958	          var affixType = this.affixedType;
8959
8960	          if (colliderTop <= dims.containerTop || dims.containerHeight <= dims.sidebarHeight) {
8961	            dims.translateY = 0;
8962	            affixType = 'STATIC';
8963	          } else {
8964	            affixType = 'up' === this.direction ? this._getAffixTypeScrollingUp() : this._getAffixTypeScrollingDown();
8965	          }
8966
8967	          // Make sure the translate Y is not bigger than container height.
8968	          dims.translateY = Math.max(0, dims.translateY);
8969	          dims.translateY = Math.min(dims.containerHeight, dims.translateY);
8970	          dims.translateY = Math.round(dims.translateY);
8971
8972	          dims.lastViewportTop = dims.viewportTop;
8973	          return affixType;
8974	        }
8975	      }, {
8976	        key: '_getAffixTypeScrollingDown',
8977	        value: function _getAffixTypeScrollingDown() {
8978	          var dims = this.dimensions;
8979	          var sidebarBottom = dims.sidebarHeight + dims.containerTop;
8980	          var colliderTop = dims.viewportTop + dims.topSpacing;
8981	          var colliderBottom = dims.viewportBottom - dims.bottomSpacing;
8982	          var affixType = this.affixedType;
8983
8984	          if (this.isSidebarFitsViewport()) {
8985	            if (dims.sidebarHeight + colliderTop >= dims.containerBottom) {
8986	              dims.translateY = dims.containerBottom - sidebarBottom;
8987	              affixType = 'CONTAINER-BOTTOM';
8988	            } else if (colliderTop >= dims.containerTop) {
8989	              dims.translateY = colliderTop - dims.containerTop;
8990	              affixType = 'VIEWPORT-TOP';
8991	            }
8992	          } else {
8993	            if (dims.containerBottom <= colliderBottom) {
8994	              dims.translateY = dims.containerBottom - sidebarBottom;
8995	              affixType = 'CONTAINER-BOTTOM';
8996	            } else if (sidebarBottom + dims.translateY <= colliderBottom) {
8997	              dims.translateY = colliderBottom - sidebarBottom;
8998	              affixType = 'VIEWPORT-BOTTOM';
8999	            } else if (dims.containerTop + dims.translateY <= colliderTop && 0 !== dims.translateY && dims.maxTranslateY !== dims.translateY) {
9000	              affixType = 'VIEWPORT-UNBOTTOM';
9001	            }
9002	          }
9003
9004	          return affixType;
9005	        }
9006	      }, {
9007	        key: '_getAffixTypeScrollingUp',
9008	        value: function _getAffixTypeScrollingUp() {
9009	          var dims = this.dimensions;
9010	          var sidebarBottom = dims.sidebarHeight + dims.containerTop;
9011	          var colliderTop = dims.viewportTop + dims.topSpacing;
9012	          var colliderBottom = dims.viewportBottom - dims.bottomSpacing;
9013	          var affixType = this.affixedType;
9014
9015	          if (colliderTop <= dims.translateY + dims.containerTop) {
9016	            dims.translateY = colliderTop - dims.containerTop;
9017	            affixType = 'VIEWPORT-TOP';
9018	          } else if (dims.containerBottom <= colliderBottom) {
9019	            dims.translateY = dims.containerBottom - sidebarBottom;
9020	            affixType = 'CONTAINER-BOTTOM';
9021	          } else if (!this.isSidebarFitsViewport()) {
9022
9023	            if (dims.containerTop <= colliderTop && 0 !== dims.translateY && dims.maxTranslateY !== dims.translateY) {
9024	              affixType = 'VIEWPORT-UNBOTTOM';
9025	            }
9026	          }
9027
9028	          return affixType;
9029	        }
9030	      }, {
9031	        key: '_getStyle',
9032	        value: function _getStyle(affixType) {
9033	          if ('undefined' === typeof affixType) return;
9034
9035	          var style = { inner: {}, outer: {} };
9036	          var dims = this.dimensions;
9037
9038	          switch (affixType) {
9039	            case 'VIEWPORT-TOP':
9040	              style.inner = { position: 'fixed', top: dims.topSpacing,
9041	                left: dims.sidebarLeft - dims.viewportLeft, width: dims.sidebarWidth };
9042	              break;
9043	            case 'VIEWPORT-BOTTOM':
9044	              style.inner = { position: 'fixed', top: 'auto', left: dims.sidebarLeft,
9045	                bottom: dims.bottomSpacing, width: dims.sidebarWidth };
9046	              break;
9047	            case 'CONTAINER-BOTTOM':
9048	            case 'VIEWPORT-UNBOTTOM':
9049	              var translate = this._getTranslate(0, dims.translateY + 'px');
9050	              if (translate && this.options.withTransForms) style.inner = { transform: translate };else style.inner = { position: 'absolute', top: dims.translateY, width: dims.sidebarWidth };
9051	              break;
9052	          }
9053
9054	          switch (affixType) {
9055	            case 'VIEWPORT-TOP':
9056	            case 'VIEWPORT-BOTTOM':
9057	            case 'VIEWPORT-UNBOTTOM':
9058	            case 'CONTAINER-BOTTOM':
9059	              style.outer = { position: 'relative' };
9060	              break;
9061	          }
9062
9063	          style.outer = StickySidebar.extend({ height: '', position: '' }, style.outer);
9064	          style.inner = StickySidebar.extend({ position: 'relative', top: '', left: '',
9065	            bottom: '', width: '', transform: '' }, style.inner);
9066
9067	          return style;
9068	        }
9069	      }, {
9070	        key: 'stickyPosition',
9071	        value: function stickyPosition(force) {
9072	          if (this._breakpoint) {
9073	            return;
9074	          };
9075
9076	          force = this._reStyle || force || false;
9077
9078	          var offsetTop = this.options.topSpacing;
9079	          var offsetBottom = this.options.bottomSpacing;
9080
vendor: 5,738 bytes, lines 9081-9213
9081	          var affixType = this.getAffixType();
9082	          var style = this._getStyle(affixType);
9083
9084	          if ((this.affixedType != affixType || force) && affixType) {
9085	            var affixEvent = 'affix.' + affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY;
9086	            StickySidebar.eventTrigger(this.sidebar, affixEvent);
9087
9088	            if ('STATIC' === affixType) StickySidebar.removeClass(this.sidebar, this.options.stickyClass);else StickySidebar.addClass(this.sidebar, this.options.stickyClass);
9089
9090	            for (var key in style.outer) {
9091	              var unit = 'number' === typeof style.outer[key] ? 'px' : '';
9092	              this.sidebar.style[key] = style.outer[key] + unit;
9093	            }
9094
9095	            for (var _key in style.inner) {
9096	              var _unit = 'number' === typeof style.inner[_key] ? 'px' : '';
9097	              this.sidebarInner.style[_key] = style.inner[_key] + _unit;
9098	            }
9099
9100	            var affixedEvent = 'affixed.' + affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY;
9101	            StickySidebar.eventTrigger(this.sidebar, affixedEvent);
9102	          } else {
9103	            if (this._initialized) this.sidebarInner.style.left = (style.inner.left);
9104	          }
9105
9106	          this.affixedType = affixType;
9107	        }
9108	      }, {
9109	        key: '_widthBreakpoint',
9110	        value: function _widthBreakpoint() {
9111	          if (window.innerWidth <= this.options.minWidth) {
9112	            this.sidebar.removeAttribute('style');
9113	            StickySidebar.removeClass(this.sidebar, this.options.stickyClass);
9114	            this.sidebarInner.removeAttribute('style');
9115	            if(!this._breakpoint) {
9116	              StickySidebar.eventTrigger(this.sidebar, 'affix.breakpoint.stickySidebar');
9117	            }
9118	            this._breakpoint = true;
9119	            this.affixedType = 'STATIC';
9120	          } else {
9121	            this._breakpoint = false;
9122	          }
9123	        }
9124	      }, {
9125	        key: 'updateSticky',
9126	        value: function updateSticky() {
9127	          var _this3 = this;
9128
9129	          var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
9130
9131	          if (this._running) return;
9132	          this._running = true;
9133
9134	          (function (eventType) {
9135	            requestAnimationFrame(function () {
9136	              switch (eventType) {
9137	                // When browser is scrolling and re-calculate just dimensions
9138	                // within scroll.
9139	                case 'scroll':
9140	                  _this3._calcDimensionsWithScroll();
9141	                  _this3.observeScrollDir();
9142	                  _this3.stickyPosition();
9143	                  break;
9144
9145	                // When browser is resizing or there's no event, observe width
9146	                // breakpoint and re-calculate dimensions.
9147	                case 'resize':
9148	                default:
9149	                  _this3._widthBreakpoint();
9150	                  _this3.calcDimensions();
9151	                  _this3.stickyPosition(true);
9152	                  break;
9153	              }
9154	              _this3._running = false;
9155	            });
9156	          })(event.type);
9157	        }
9158	      }, {
9159	        key: '_setSupportFeatures',
9160	        value: function _setSupportFeatures() {
9161	          var support = this.support;
9162
9163	          support.transform = StickySidebar.supportTransform();
9164	          support.transform3d = StickySidebar.supportTransform(true);
9165	        }
9166	      }, {
9167	        key: '_getTranslate',
9168	        value: function _getTranslate() {
9169	          var y = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
9170	          var x = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
9171	          var z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
9172
9173	          if (this.support.transform3d) return 'translate3d(' + y + ', ' + x + ', ' + z + ')';else if (this.support.translate) return 'translate(' + y + ', ' + x + ')';else return false;
9174	        }
9175	      }, {
9176	        key: 'destroy',
9177	        value: function destroy() {
9178	          window.removeEventListener('resize', this, { capture: false });
9179	          window.removeEventListener('scroll', this, { capture: false });
9180
9181	          this.sidebar.classList.remove(this.options.stickyClass);
9182	          this.sidebar.style.minHeight = '';
9183
9184	          this.sidebar.removeEventListener('update' + EVENT_KEY, this);
9185
9186	          var styleReset = { inner: {}, outer: {} };
9187
9188	          styleReset.inner = { position: '', top: '', left: '', bottom: '', width: '', transform: '' };
9189	          styleReset.outer = { height: '', position: '' };
9190
9191	          for (var key in styleReset.outer) {
9192	            this.sidebar.style[key] = styleReset.outer[key];
9193	          }for (var _key2 in styleReset.inner) {
9194	            this.sidebarInner.style[_key2] = styleReset.inner[_key2];
9195	          }if (this.options.resizeSensor && 'undefined' !== typeof ResizeSensor) {
9196	            ResizeSensor.detach(this.sidebarInner, this.handleEvent);
9197	            ResizeSensor.detach(this.container, this.handleEvent);
9198	          }
9199	        }
9200	      }], [{
9201	        key: 'supportTransform',
9202	        value: function supportTransform(transform3d) {
9203	          var result = false,
9204	              property = transform3d ? 'perspective' : 'transform',
9205	              upper = property.charAt(0).toUpperCase() + property.slice(1),
9206	              prefixes = ['Webkit', 'Moz', 'O', 'ms'],
9207	              support = document.createElement('support'),
9208	              style = support.style;
9209
9210	          (property + ' ' + prefixes.join(upper + ' ') + upper).split(' ').forEach(function (property, i) {
9211	            if (style[property] !== undefined) {
9212	              result = property;
9213	              return false;
9214	            }
9215	          });
9216	          return result;
9217	        }
9218	      }, {
9219	        key: 'eventTrigger',
9220	        value: function eventTrigger(element, eventName, data) {
9221	          try {
9222	            var event = new CustomEvent(eventName, { detail: data });
9223	          } catch (e) {
9224	            var event = document.createEvent('CustomEvent');
9225	            event.initCustomEvent(eventName, true, true, data);
9226	          }
9227	          element.dispatchEvent(event);
9228	        }
9229	      }, {
9230	        key: 'extend',
9231	        value: function extend(defaults, options) {
9232	          var results = {};
9233	          for (var key in defaults) {
9234	            if ('undefined' !== typeof options[key]) results[key] = options[key];else results[key] = defaults[key];
9235	          }
9236	          return results;
9237	        }
9238	      }, {
9239	        key: 'offsetRelative',
9240	        value: function offsetRelative(element) {
9241	          var result = { left: 0, top: 0 };
9242
9243	          do {
9244	            var offsetTop = element.offsetTop;
9245	            var offsetLeft = element.offsetLeft;
9246
9247	            if (!isNaN(offsetTop)) result.top += offsetTop;
9248
9249	            if (!isNaN(offsetLeft)) result.left += offsetLeft;
9250
9251	            element = 'BODY' === element.tagName ? element.parentElement : element.offsetParent;
9252	          } while (element);
9253	          return result;
9254	        }
9255	      }, {
9256	        key: 'addClass',
9257	        value: function addClass(element, className) {
9258	          if (!StickySidebar.hasClass(element, className)) {
9259	            if (element.classList) element.classList.add(className);else element.className += ' ' + className;
9260	          }
9261	        }
9262	      }, {
9263	        key: 'removeClass',
9264	        value: function removeClass(element, className) {
9265	          if (StickySidebar.hasClass(element, className)) {
9266	            if (element.classList) element.classList.remove(className);else element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
9267	          }
9268	        }
9269	      }, {
9270	        key: 'hasClass',
9271	        value: function hasClass(element, className) {
9272	          if (element.classList) return element.classList.contains(className);else return new RegExp('(^| )' + className + '( |$)', 'gi').test(element.className);
9273	        }
9274	      }, {
9275	        key: 'defaults',
9276	        get: function () {
9277	          return DEFAULTS;
9278	        }
9279	      }]);
9280
9281	      return StickySidebar;
9282	    }();
9283
9284	    return StickySidebar;
9285	  }();
9286
9287	  exports.default = StickySidebar;
9288
9289
9290	  // Global
9291	  // -------------------------
9292	  window.StickySidebar = StickySidebar;
9293	});
9294	});
9295
9296	var stickySidebar$1 = unwrapExports(stickySidebar);
9297
9298	exports['default'] = stickySidebar$1;
9299	exports.__moduleExports = stickySidebar;
9300
9301	Object.defineProperty(exports, '__esModule', { value: true });
9302
9303	})));
9304
9305	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
9306
9307/***/ }),
9308
9309/***/ 329:
9310/***/ (function(module, exports) {
9311
9312	window.AccordionView = (function () {
9313	  function onAccordionTitleClick(event) {
9314	    return event.target.classList.toggle('active');
9315	  }
9316
9317	  function create(element) {
9318	    if (typeof element !== 'undefined' && element != null) {
9319	      element
9320	        .querySelectorAll('.accordion-item > .accordion-title')
9321	        .forEach(function (e) {
9322	          e.addEventListener('click', onAccordionTitleClick);
9323	        });
9324	    }
9325	  }
9326
9327	  return {
9328	    create,
9329	  };
9330	})();
9331
9332
9333/***/ }),
9334
9335/***/ 330:
9336/***/ (function(module, exports) {
9337
9338	window.ScrollableTabs = (function () {
9339	  function createHandleScroll(container) {
9340	    function handleScroll(e) {
9341	      const target = e.target;
9342
9343	      const firstHeaderRect = target.firstElementChild.getBoundingClientRect();
9344	      const lastHeaderRect = target.lastElementChild.getBoundingClientRect();
9345
9346	      container
9347	        .querySelector('[role=scroll-arrow].left')
9348	        .classList.toggle(
9349	          'invisible',
9350	          target.scrollLeft <= firstHeaderRect.left
9351	        );
9352
9353	      let observer;
9354
9355	      let options = {
9356	        root: null,
9357	        rootMargin: "0px",
9358	        threshold: 1.0
9359	      };
9360
9361	      observer = new IntersectionObserver(hideRightArrow, options);
9362	      observer.observe(target.lastElementChild);
9363
9364	    }
9365
9366	    if (typeof window._ !== 'undefined') {
9367	      return _.debounce(handleScroll, 300);
9368	    } else {
9369	      return handleScroll;
9370	    }
9371	  }
9372
9373	  function hideRightArrow(entries) {
9374	    entries.forEach((entry) => {
9375	      const rightArrow = document.querySelector(".scrollable-tabs-headers__arrow.right");
9376
9377	      if (entry.isIntersecting) {
9378	        rightArrow.style.display = "none";
9379	      } else {
9380	        rightArrow.style.display = "block";
9381	      }
9382	    });
9383	  }
9384
9385	  function handleScrollArrowClick(e) {
9386	    const isLeftScroll =
9387	      e.target.getAttribute('data-scroll-direction') === 'left';
9388
9389	    const headers = e.target.parentElement.querySelector(
9390	      '.scrollable-tabs-headers'
9391	    );
9392	    headers.scrollBy({
9393	      left: isLeftScroll ? -100 : 100,
9394	      top: 0,
9395	      behavior: 'smooth',
9396	    });
9397	  }
9398
9399	  function onHeaderClick(event) {
9400	    const itemId = event.target.getAttribute('data-item-id');
9401	    if (
9402	      typeof itemId === 'undefined' ||
9403	      itemId == null ||
9404	      event.target.classList.contains('active')
9405	    ) {
9406	      return;
9407	    }
9408
9409	    document
9410	      .querySelectorAll(
9411	        '.scrollable-tabs-headers__title, .scrollable-tabs-contents__content'
9412	      )
9413	      .forEach((item) => item.classList.remove('active'));
9414
9415	    event.target.classList.add('active');
9416	    document
9417	      .querySelector(
9418	        `.scrollable-tabs-contents__content[data-item-id="${itemId}"]`
9419	      )
9420	      .classList.add('active');
9421
9422	    event.target.scrollIntoView({
9423	      behavior: 'smooth',
9424	      block: 'nearest',
9425	    });
9426	  }
9427
9428	  function createContentFromData(container, data) {
9429	    const headers = container.querySelector('.scrollable-tabs-headers');
9430	    const headersContainer = container.querySelector(
9431	      '.scrollable-tabs-headers__container'
9432	    );
9433	    const contents = container.querySelector('.scrollable-tabs-contents');
9434
9435	    data.forEach((item, i) => {
9436	      if (typeof item === 'undefined' || typeof item.title === 'undefined') {
9437	        return false;
9438	      }
9439
9440	      const header = document.createElement('div');
9441
9442	      header.classList.add('scrollable-tabs-headers__title');
9443	      header.setAttribute('data-item-id', i);
9444
9445	      if (typeof item.title === 'object') {
9446	        header.append(item.title);
9447	      } else {
9448	        header.innerHTML = item.title;
9449	      }
9450
9451	      const content = document.createElement('div');
9452	      content.classList.add('scrollable-tabs-contents__content');
9453	      content.setAttribute('data-item-id', i);
9454	      if (typeof item.text === 'object') {
9455	        if (Array.isArray(item.text)) {
9456	          item.text.forEach(function (x) {
9457	            content.append(x);
9458	          });
9459	        } else {
9460	          content.append(item.text);
9461	        }
9462	      } else {
9463	        content.innerHTML = item.text;
9464	      }
9465
9466	      if (i === 0) {
9467	        header.classList.add('active');
9468	        content.classList.add('active');
9469	      }
9470
9471	      headers.append(header);
9472	      contents.append(content);
9473
9474	      return true;
9475	    });
9476
9477	    headersContainer.firstElementChild.insertAdjacentElement(
9478	      'afterend',
9479	      headers
9480	    );
9481	    container.append(headersContainer, contents);
9482	  }
9483
9484	  function init(element) {
9485	    const headers = element.querySelector('.scrollable-tabs-headers');
9486	    const headersContainer = element.querySelector(
9487	      '.scrollable-tabs-headers__container'
9488	    );
9489
9490	    headersContainer
9491	      .querySelectorAll('[role=scroll-arrow]')
9492	      .forEach((el) => el.addEventListener('click', handleScrollArrowClick));
9493
9494	    headersContainer
9495	      .querySelectorAll('.scrollable-tabs-headers__title')
9496	      .forEach((el) => el.addEventListener('click', onHeaderClick));
9497
9498	    headers.addEventListener('scroll', createHandleScroll(headersContainer));
9499	  }
9500	  return {
9501	    init,
9502	    createContentFromData: function (container, data) {
9503	      createContentFromData(container, data);
9504	      init(container);
9505	    },
9506	  };
9507	})();
9508
9509	window.BranchDirectionParser = (function () {
9510	  function parse(apiContent, cmsContent) {
9511	    function getDirections(arr) {
9512	      return arr.reduce((acc, element) => {
9513	        const header = element.children[0];
9514	        acc.push({
9515	          title: header,
9516	          text: element.children[1],
9517	        });
9518
9519	        return acc;
9520	      }, []);
9521	    }
9522
9523	    function getOthers(arr) {
9524	      const title = arr.shift();
9525	      return [{ title, text: arr }];
9526	    }
9527
9528	    function getContentAsElement(content) {
9529	      const div = document.createElement('div');
9530	      div.innerHTML = content;
9531	      return div;
9532	    }
9533
9534	    function getDirectionsFromCms(element) {
9535	      let arrayOfElemets = [...element.children];
9536
9537	      arrayOfElemets.splice(
9538	        0,
9539	        arrayOfElemets.findIndex((x) => x.tagName === 'H3')
9540	      );
9541
9542	      return getOthers(arrayOfElemets);
9543	    }
9544
9545	    function getDirectionsFromApi(element) {
9546	      let arrayOfElemets = [...element.children];
9547	      return getDirections(arrayOfElemets);
9548	    }
9549
9550	    function parseDirections() {
9551	      const parsedCmsContent = getContentAsElement(cmsContent);
9552	      const parsedApiContent = getContentAsElement(apiContent);
9553
9554	      return [
9555	        ...getDirectionsFromApi(parsedApiContent),
9556	        ...getDirectionsFromCms(parsedCmsContent),
9557	      ];
9558	    }
9559
9560	    return parseDirections();
9561	  }
9562	  return { parse };
9563	})();
9564
9565
9566/***/ }),
9567
9568/***/ 331:
9569/***/ (function(module, exports, __webpack_require__) {
9570
9571	__webpack_require__(332);
9572	__webpack_require__(333);
9573	__webpack_require__(334);
9574	__webpack_require__(335);
9575	__webpack_require__(336);
9576	__webpack_require__(337);
9577	__webpack_require__(338);
9578	__webpack_require__(339);
9579
9580	$(function(){
9581	  $(document).trigger('bv:init')
9582	    .on('click', 'form [data-bv-submit]', function(e) {
9583	      $(e.currentTarget).closest('form').submit();
9584	    })
9585	    .on('success.form.bv', 'form', function(e) {
9586	      $(e.currentTarget).bootstrapValidator('defaultSubmit');
9587	    })
9588	    .on('select-auto-json:init',function(){
9589	      $('*[data-select-auto-json]').each(function(ind, obj){
9590	        $controlWrap = $(obj).parents('.control-fx');
9591
9592	        if ($controlWrap.hasClass('current-selection')){
9593	          $(obj).trigger('enable');
9594	        } else if (!$(obj).is(':disabled') && !$controlWrap.before().hasClass('current-selection')){
9595	          $(obj).trigger('enable');
9596	          $controlWrap.addClass('current-selection');
9597	        }
9598	      });
9599	      $('select[data-initial-value]').trigger('select:set-initial-value');
9600	    })
9601	    .trigger('select-auto-json:init');
9602	});
9603
9604
9605/***/ }),
9606
9607/***/ 332:
9608/***/ (function(module, exports) {
9609
9610	/**
9611	 * BootstrapValidator (http://bootstrapvalidator.com)
9612	 * The best jQuery plugin to validate form fields. Designed to use with Bootstrap 3
9613	 *
9614	 * @author      https://twitter.com/nghuuphuoc
9615	 * @copyright   (c) 2013 - 2014 Nguyen Huu Phuoc
9616	 * @license     Commercial: http://bootstrapvalidator.com/license/
9617	 *              Non-commercial: http://creativecommons.org/licenses/by-nc-nd/3.0/
9618	 */
9619
9620	(function($) {
9621	  var BootstrapValidator = function(form, options) {
9622	    this.$form   = $(form);
9623	    this.options = $.extend({}, $.fn.bootstrapValidator.DEFAULT_OPTIONS, options);
9624
9625	    this.$invalidFields = $([]);    // Array of invalid fields
9626	    this.$submitButton  = null;     // The submit button which is clicked to submit form
9627	    this.$hiddenButton  = null;
9628
9629	    // Validating status
9630	    this.STATUS_NOT_VALIDATED = 'NOT_VALIDATED';
9631	    this.STATUS_VALIDATING    = 'VALIDATING';
9632	    this.STATUS_INVALID       = 'INVALID';
9633	    this.STATUS_VALID         = 'VALID';
9634
9635	    // Determine the event that is fired when user change the field value
9636	    // Most modern browsers supports input event except IE 7, 8.
9637	    // IE 9 supports input event but the event is still not fired if I press the backspace key.
9638	    // Get IE version
9639	    // https://gist.github.com/padolsey/527683/#comment-7595
9640	    var ieVersion = (function() {
9641	      var v = 3, div = document.createElement('div'), a = div.all || [];
9642	      while (div.innerHTML = '<!--[if gt IE '+(++v)+']><br><![endif]-->', a[0]) {}
9643	      return v > 4 ? v : !v;
9644	    }());
9645
9646	    var el = document.createElement('div');
9647	    this._changeEvent = (ieVersion === 9 || !('oninput' in el)) ? 'keyup' : 'input';
9648
9649	    // The flag to indicate that the form is ready to submit when a remote/callback validator returns
9650	    this._submitIfValid = null;
9651
9652	    // Field elements
9653	    this._cacheFields = {};
9654
9655	    this._init();
9656	  };
9657
9658	  BootstrapValidator.prototype = {
9659	    constructor: BootstrapValidator,
9660
9661	    /**
9662	     * Init form
9663	     */
9664	    _init: function() {
9665	      var that    = this,
9666	        options = {
9667	          autoFocus:      this.$form.attr('data-bv-autofocus'),
9668	          container:      this.$form.attr('data-bv-container'),
9669	          events: {
9670	            formInit:         this.$form.attr('data-bv-events-form-init'),
9671	            formError:        this.$form.attr('data-bv-events-form-error'),
9672	            formSuccess:      this.$form.attr('data-bv-events-form-success'),
9673	            fieldAdded:       this.$form.attr('data-bv-events-field-added'),
9674	            fieldRemoved:     this.$form.attr('data-bv-events-field-removed'),
9675	            fieldInit:        this.$form.attr('data-bv-events-field-init'),
9676	            fieldError:       this.$form.attr('data-bv-events-field-error'),
9677	            fieldSuccess:     this.$form.attr('data-bv-events-field-success'),
9678	            fieldStatus:      this.$form.attr('data-bv-events-field-status'),
9679	            validatorError:   this.$form.attr('data-bv-events-validator-error'),
9680	            validatorSuccess: this.$form.attr('data-bv-events-validator-success')
9681	          },
9682	          excluded:       this.$form.attr('data-bv-excluded'),
9683	          feedbackIcons: {
9684	            valid:      this.$form.attr('data-bv-feedbackicons-valid'),
9685	            invalid:    this.$form.attr('data-bv-feedbackicons-invalid'),
9686	            validating: this.$form.attr('data-bv-feedbackicons-validating')
9687	          },
9688	          group:          this.$form.attr('data-bv-group'),
9689	          live:           this.$form.attr('data-bv-live'),
9690	          message:        this.$form.attr('data-bv-message'),
9691	          onError:        this.$form.attr('data-bv-onerror'),
9692	          onSuccess:      this.$form.attr('data-bv-onsuccess'),
9693	          submitButtons:  this.$form.attr('data-bv-submitbuttons'),
9694	          threshold:      this.$form.attr('data-bv-threshold'),
9695	          trigger:        this.$form.attr('data-bv-trigger'),
9696	          verbose:        this.$form.attr('data-bv-verbose'),
9697	          fields:         {}
9698	        };
9699
9700	      this.$form
9701	        // Disable client side validation in HTML 5
9702	        .attr('novalidate', 'novalidate')
9703	        .addClass(this.options.elementClass)
9704	        // Disable the default submission first
9705	        .on('submit.bv', function(e) {
9706	          e.preventDefault();
9707	          that.validate();
9708	        })
9709	        .on('click.bv', this.options.submitButtons, function() {
9710	          that.$submitButton  = $(this);
9711	          // The user just click the submit button
9712	          that._submitIfValid = true;
9713	        })
9714	        // Find all fields which have either "name" or "data-bv-field" attribute
9715	        .find('[name], [data-bv-field]')
9716	        .each(function() {
9717	          var $field = $(this),
9718	            field  = $field.attr('name') || $field.attr('data-bv-field'),
9719	            opts   = that._parseOptions($field);
9720	          if (opts) {
9721	            $field.attr('data-bv-field', field);
9722	            options.fields[field] = $.extend({}, opts, options.fields[field]);
9723	          }
9724	        });
9725
9726	      this.options = $.extend(true, this.options, options);
9727
9728	      // When pressing Enter on any field in the form, the first submit button will do its job.
9729	      // The form then will be submitted.
9730	      // I create a first hidden submit button
9731	      this.$hiddenButton = $('<button/>')
9732	        .attr('type', 'submit')
9733	        .prependTo(this.$form)
9734	        .addClass('bv-hidden-submit')
9735	        .css({ display: 'none', width: 0, height: 0 });
9736
9737	      this.$form
9738	        .on('click.bv', '[type="submit"]', function(e) {
9739	          // #746: Check if the button click handler returns false
9740	          if (!e.isDefaultPrevented()) {
9741	            var $target = $(e.target),
9742	            // The button might contain HTML tag
9743	              $button = $target.is('[type="submit"]') ? $target.eq(0) : $target.parent('[type="submit"]').eq(0);
9744
9745	            // Don't perform validation when clicking on the submit button/input
9746	            // which aren't defined by the 'submitButtons' option
9747	            if (that.options.submitButtons && !$button.is(that.options.submitButtons) && !$button.is(that.$hiddenButton)) {
9748	              that.$form.off('submit.bv').submit();
9749	            }
9750	          }
9751	        });
9752
9753	      for (var field in this.options.fields) {
9754	        this._initField(field);
9755	      }
9756
9757	      this.$form.trigger($.Event(this.options.events.formInit), {
9758	        bv: this,
9759	        options: this.options
9760	      });
9761
9762	      // Prepare the events
9763	      if (this.options.onSuccess) {
9764	        this.$form.on(this.options.events.formSuccess, function(e) {
9765	          $.fn.bootstrapValidator.helpers.call(that.options.onSuccess, [e]);
9766	        });
9767	      }
9768	      if (this.options.onError) {
9769	        this.$form.on(this.options.events.formError, function(e) {
9770	          $.fn.bootstrapValidator.helpers.call(that.options.onError, [e]);
9771	        });
9772	      }
9773	    },
9774
9775	    /**
9776	     * Parse the validator options from HTML attributes
9777	     *
9778	     * @param {jQuery} $field The field element
9779	     * @returns {Object}
9780	     */
9781
9782	    _parseOptions: function($field) {
9783	      var field      = $field.attr('name') || $field.attr('data-bv-field'),
9784	        validators = {},
9785	        validator,
9786	        v,          // Validator name
9787	        attrName,
9788	        enabled,
9789	        optionName,
9790	        optionAttrName,
9791	        optionValue,
9792	        html5AttrName,
9793	        html5AttrMap;
9794	      for (v in $.fn.bootstrapValidator.validators) {
9795	        validator    = $.fn.bootstrapValidator.validators[v];
9796	        attrName     = 'data-bv-' + v.toLowerCase();
9797	        enabled      = $field.attr(attrName) + '';
9798	        html5AttrMap = ('function' === typeof validator.enableByHtml5) ? validator.enableByHtml5($field) : null;
9799	        if ( (html5AttrMap && enabled !== 'false') ||
9800	          (html5AttrMap !== true && ('' === enabled || 'true' === enabled || attrName === enabled.toLowerCase())))
9801	        {
9802	          // Try to parse the options via attributes
9803	          validator.html5Attributes = $.extend({}, { message: 'message', onerror: 'onError', onsuccess: 'onSuccess' }, validator.html5Attributes);
9804	          validators[v] = $.extend({}, html5AttrMap === true ? {} : html5AttrMap, validators[v]);
9805
9806	          for (html5AttrName in validator.html5Attributes) {
9807	            optionName  = validator.html5Attributes[html5AttrName];
9808	            optionAttrName = 'data-bv-' + v.toLowerCase() + '-' + html5AttrName;
9809	            optionValue = $field.attr(optionAttrName);
9810	            if (optionValue) {
9811	              if ('true' === optionValue || optionAttrName === optionValue.toLowerCase()) {
9812	                optionValue = true;
9813	              } else if ('false' === optionValue) {
9814	                optionValue = false;
9815	              }
9816	              validators[v][optionName] = optionValue;
9817	            }
9818	          }
9819	        }
9820	      }
9821
9822	      var opts = {
9823	          autoFocus:     $field.attr('data-bv-autofocus'),
9824	          container:     $field.attr('data-bv-container'),
9825	          excluded:      $field.attr('data-bv-excluded'),
9826	          feedbackIcons: $field.attr('data-bv-feedbackicons'),
9827	          group:         $field.attr('data-bv-group'),
9828	          message:       $field.attr('data-bv-message'),
9829	          onError:       $field.attr('data-bv-onerror'),
9830	          onStatus:      $field.attr('data-bv-onstatus'),
9831	          onSuccess:     $field.attr('data-bv-onsuccess'),
9832	          selector:      $field.attr('data-bv-selector'),
9833	          threshold:     $field.attr('data-bv-threshold'),
9834	          trigger:       $field.attr('data-bv-trigger'),
9835	          verbose:       $field.attr('data-bv-verbose'),
9836	          validators:    validators
9837	        },
9838	        emptyOptions    = $.isEmptyObject(opts),        // Check if the field options are set using HTML attributes
9839	        emptyValidators = $.isEmptyObject(validators);  // Check if the field validators are set using HTML attributes
9840
9841	      if (!emptyValidators || (!emptyOptions && this.options.fields && this.options.fields[field])) {
9842	        opts.validators = validators;
9843	        return opts;
9844	      } else {
9845	        return null;
9846	      }
9847	    },
9848
9849	    /**
9850	     * Init field
9851	     *
9852	     * @param {String|jQuery} field The field name or field element
9853	     */
9854	    _initField: function(field) {
9855	      var fields = $([]);
9856	      switch (typeof field) {
9857	        case 'object':
9858	          fields = field;
9859	          field  = field.attr('data-bv-field');
9860	          break;
9861	        case 'string':
9862	          fields = this.getFieldElements(field);
9863	          fields.attr('data-bv-field', field);
9864	          break;
9865	        default:
9866	          break;
9867	      }
9868
9869	      // We don't need to validate non-existing fields
9870	      if (fields.length === 0) {
9871	        return;
9872	      }
9873
9874	      if (this.options.fields[field] === null || this.options.fields[field].validators === null) {
9875	        return;
9876	      }
9877
9878	      var validatorName;
9879	      for (validatorName in this.options.fields[field].validators) {
9880	        if (!$.fn.bootstrapValidator.validators[validatorName]) {
9881	          delete this.options.fields[field].validators[validatorName];
9882	        }
9883	      }
9884	      if (this.options.fields[field].enabled === null) {
9885	        this.options.fields[field].enabled = true;
9886	      }
9887
9888	      var that      = this,
9889	        total     = fields.length,
9890	        type      = fields.attr('type'),
9891	        updateAll = (total === 1) || ('radio' === type) || ('checkbox' === type),
9892	        event     = ('radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === fields.eq(0).get(0).tagName) ? 'change' : this._changeEvent,
9893	        trigger   = (this.options.fields[field].trigger || this.options.trigger || event).split(' '),
9894	        events    = $.map(trigger, function(item) {
9895	          return item + '.update.bv';
9896	        }).join(' ');
9897
9898	      for (var i = 0; i < total; i++) {
9899	        var $field    = fields.eq(i),
9900	          group     = this.options.fields[field].group || this.options.group,
9901	          $parent   = $field.parents(group),
9902	        // Allow user to indicate where the error messages are shown
9903	          container = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container),
9904	          $message  = (container && container !== 'tooltip' && container !== 'popover') ? $(container) : this._getMessageContainer($field, group);
9905
9906	        if (container && container !== 'tooltip' && container !== 'popover') {
9907	          $message.addClass('has-error');
9908	        }
9909
9910	        // Remove all error messages and feedback icons
9911	        $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove();
9912	        $parent.find('i[data-bv-icon-for="' + field + '"]').remove();
9913
9914	        // Whenever the user change the field value, mark it as not val
9914idated yet
9915	        /*jshint -W083 */
9916	        $field.off(events).on(events, function() {
9917	          that.updateStatus($(this), that.STATUS_NOT_VALIDATED);
9918	        });
9919
9920	        // Create help block elements for showing the error messages
9921	        $field.data('bv.messages', $message);
9922	        for (validatorName in this.options.fields[field].validators) {
9923	          $field.data('bv.result.' + validatorName, this.STATUS_NOT_VALIDATED);
9924
9925	          if (!updateAll || i === total - 1) {
9926	            $('<small/>')
9927	              .css('display', 'none')
9928	              .addClass('help-block')
9929	              .attr('data-bv-validator', validatorName)
9930	              .attr('data-bv-for', field)
9931	              .attr('data-bv-result', this.STATUS_NOT_VALIDATED)
9932	              .html(this._getMessage(field, validatorName))
9933	              .appendTo($message);
9934	          }
9935
9936	          // Init the validator
9937	          if ('function' === typeof $.fn.bootstrapValidator.validators[validatorName].init) {
9938	            $.fn.bootstrapValidator.validators[validatorName].init(this, $field, this.options.fields[field].validators[validatorName]);
9939	          }
9940	        }
9941
9942	        // Prepare the feedback icons
9943	        // Available from Bootstrap 3.1 (http://getbootstrap.com/css/#forms-control-validation)
9944	        if (this.options.fields[field].feedbackIcons !== false &&
9945	          this.options.fields[field].feedbackIcons !== 'false' &&
9946	          this.options.feedbackIcons &&
9947	          this.options.feedbackIcons.validating &&
9948	          this.options.feedbackIcons.invalid &&
9949	          this.options.feedbackIcons.valid &&
9950	          (!updateAll || i === total - 1))
9951	        {
9952	          // $parent.removeClass('has-success').removeClass('has-error').addClass('has-feedback');
9953	          // Keep error messages which are populated from back-end
9954	          $parent.addClass('has-feedback');
9955	          var $icon = $('<i/>')
9956	            .css('display', 'none')
9957	            .addClass('form-control-feedback')
9958	            .attr('data-bv-icon-for', field)
9959	            .insertAfter($field);
9960
9961	          // Place it after the container of checkbox/radio
9962	          // so when clicking the icon, it doesn't effect to the checkbox/radio element
9963	          if ('checkbox' === type || 'radio' === type) {
9964	            var $fieldParent = $field.parent();
9965	            if ($fieldParent.hasClass(type)) {
9966	              $icon.insertAfter($fieldParent);
9967	            } else if ($fieldParent.parent().hasClass(type)) {
9968	              $icon.insertAfter($fieldParent.parent());
9969	            }
9970	          }
9971
9972	          // The feedback icon does not render correctly if there is no label
9973	          // https://github.com/twbs/bootstrap/issues/12873
9974	          if ($parent.find('label').length === 0) {
9975	            $icon.addClass('bv-no-label');
9976	          }
9977	          // Fix feedback icons in input-group
9978	          if ($parent.find('.input-group').length !== 0) {
9979	            $icon.addClass('bv-icon-input-group')
9980	              .insertAfter($parent.find('.input-group').eq(0));
9981	          }
9982
9983	          // Store the icon as a data of field element
9984	          if (!updateAll) {
9985	            $field.data('bv.icon', $icon);
9986	          } else if (i === total - 1) {
9987	            // All fields with the same name have the same icon
9988	            fields.data('bv.icon', $icon);
9989	          }
9990
9991	          if (container) {
9992	            $field
9993	              // Show tooltip/popover message when field gets focus
9994	              .off('focus.container.bv')
9995	              .on('focus.container.bv', function() {
9996	                switch (container) {
9997	                  case 'tooltip':
9998	                    $(this).data('bv.icon').tooltip('show');
9999	                    break;
10000	                  case 'popover':
10001	                    $(this).data('bv.icon').popover('show');
10002	                    break;
10003	                  default:
10004	                    break;
10005	                }
10006	              })
10007	              // and hide them when losing focus
10008	              .off('blur.container.bv')
10009	              .on('blur.container.bv', function() {
10010	                switch (container) {
10011	                  case 'tooltip':
10012	                    $(this).data('bv.icon').tooltip('hide');
10013	                    break;
10014	                  case 'popover':
10015	                    $(this).data('bv.icon').popover('hide');
10016	                    break;
10017	                  default:
10018	                    break;
10019	                }
10020	              });
10021	          }
10022	        }
10023	      }
10024
10025	      // Prepare the events
10026	      fields
10027	        .on(this.options.events.fieldSuccess, function(e, data) {
10028	          var onSuccess = that.getOptions(data.field, null, 'onSuccess');
10029	          if (onSuccess) {
10030	            $.fn.bootstrapValidator.helpers.call(onSuccess, [e, data]);
10031	          }
10032	        })
10033	        .on(this.options.events.fieldError, function(e, data) {
10034	          var onError = that.getOptions(data.field, null, 'onError');
10035	          if (onError) {
10036	            $.fn.bootstrapValidator.helpers.call(onError, [e, data]);
10037	          }
10038	        })
10039	        .on(this.options.events.fieldStatus, function(e, data) {
10040	          var onStatus = that.getOptions(data.field, null, 'onStatus');
10041	          if (onStatus) {
10042	            $.fn.bootstrapValidator.helpers.call(onStatus, [e, data]);
10043	          }
10044	        })
10045	        .on(this.options.events.validatorError, function(e, data) {
10046	          var onError = that.getOptions(data.field, data.validator, 'onError');
10047	          if (onError) {
10048	            $.fn.bootstrapValidator.helpers.call(onError, [e, data]);
10049	          }
10050	        })
10051	        .on(this.options.events.validatorSuccess, function(e, data) {
10052	          var onSuccess = that.getOptions(data.field, data.validator, 'onSuccess');
10053	          if (onSuccess) {
10054	            $.fn.bootstrapValidator.helpers.call(onSuccess, [e, data]);
10055	          }
10056	        });
10057
10058	      // Set live mode
10059	      events = $.map(trigger, function(item) {
10060	        return item + '.live.bv';
10061	      }).join(' ');
10062	      switch (this.options.live) {
10063	        case 'submitted':
10064	          break;
10065	        case 'disabled':
10066	          fields.off(events);
10067	          break;
10068	        case 'enabled':
10069	        /* falls through */
10070	        default:
10071	          fields.off(events).on(events, function() {
10072	            if (that._exceedThreshold($(this))) {
10073	              that.validateField($(this));
10074	            }
10075	          });
10076	          break;
10077	      }
10078
10079	      fields.trigger($.Event(this.options.events.fieldInit), {
10080	        bv: this,
10081	        field: field,
10082	        element: fields
10083	      });
10084	    },
10085
10086	    /**
10087	     * Get the error message for given field and validator
10088	     *
10089	     * @param {String} field The field name
10090	     * @param {String} validatorName The validator name
10091	     * @returns {String}
10092	     */
10093	    _getMessage: function(field, validatorName) {
10094	      if (!this.options.fields[field] || !$.fn.bootstrapValidator.validators[validatorName] ||
10095	        !this.options.fields[field].validators ||
10096	        !this.options.fields[field].validators[validatorName])
10097	      {
10098	        return '';
10099	      }
10100
10101	      var options = this.options.fields[field].validators[validatorName];
10102	      switch (true) {
10103	        case (!!options.message):
10104	          return options.message;
10105	        case (!!this.options.fields[field].message):
10106	          return this.options.fields[field].message;
10107	        case (!!$.fn.bootstrapValidator.i18n[validatorName]):
10108	          return $.fn.bootstrapValidator.i18n[validatorName]['default'];
10109	        default:
10110	          return this.options.message;
10111	      }
10112	    },
10113
10114	    /**
10115	     * Get the element to place the error messages
10116	     *
10117	     * @param {jQuery} $field The field element
10118	     * @param {String} group
10119	     * @returns {jQuery}
10120	     */
10121	    _getMessageContainer: function($field, group) {
10122	      var $parent = $field.parent();
10123	      if ($parent.is(group)) {
10124	        return $parent;
10125	      }
10126
10127	      var cssClasses = $parent.attr('class');
10128	      if (!cssClasses) {
10129	        return this._getMessageContainer($parent, group);
10130	      }
10131
10132	      cssClasses = cssClasses.split(' ');
10133	      var n = cssClasses.length;
10134	      for (var i = 0; i < n; i++) {
10135	        if (/^col-(xs|sm|md|lg)-\d+$/.test(cssClasses[i]) || /^col-(xs|sm|md|lg)-offset-\d+$/.test(cssClasses[i])) {
10136	          return $parent;
10137	        }
10138	      }
10139
10140	      return this._getMessageContainer($parent, group);
10141	    },
10142
10143	    /**
10144	     * Called when all validations are completed
10145	     */
10146	    _submit: function() {
10147	      var isValid   = this.isValid(),
10148	        eventType = isValid ? this.options.events.formSuccess : this.options.events.formError,
10149	        e         = $.Event(eventType);
10150
10151	      this.$form.trigger(e);
10152
10153	      // Call default handler
10154	      // Check if whether the submit button is clicked
10155	      if (this.$submitButton) {
10156	        this[(isValid ? '_onSuccess' : '_onError')](e);
10157	      }
10158	    },
10159
10160	    /**
10161	     * Check if the field is excluded.
10162	     * Returning true means that the field will not be validated
10163	     *
10164	     * @param {jQuery} $field The field element
10165	     * @returns {Boolean}
10166	     */
10167	    _isExcluded: function($field) {
10168	      var excludedAttr = $field.attr('data-bv-excluded'),
10169	      // I still need to check the 'name' attribute while initializing the field
10170	        field        = $field.attr('data-bv-field') || $field.attr('name');
10171
10172	      switch (true) {
10173	        case (!!field && this.options.fields && this.options.fields[field] && (this.options.fields[field].excluded === 'true' || this.options.fields[field].excluded === true)):
10174	        case (excludedAttr === 'true'):
10175	        case (excludedAttr === ''):
10176	          return true;
10177
10178	        case (!!field && this.options.fields && this.options.fields[field] && (this.options.fields[field].excluded === 'false' || this.options.fields[field].excluded === false)):
10179	        case (excludedAttr === 'false'):
10180	          return false;
10181
10182	        default:
10183	          if (this.options.excluded) {
10184	            // Convert to array first
10185	            if ('string' === typeof this.options.excluded) {
10186	              this.options.excluded = $.map(this.options.excluded.split(','), function(item) {
10187	                // Trim the spaces
10188	                return $.trim(item);
10189	              });
10190	            }
10191
10192	            var length = this.options.excluded.length;
10193	            for (var i = 0; i < length; i++) {
10194	              if (('string' === typeof this.options.excluded[i] && $field.is(this.options.excluded[i])) ||
10195	                ('function' === typeof this.options.excluded[i] && this.options.excluded[i].call(this, $field, this) === true))
10196	              {
10197	                return true;
10198	              }
10199	            }
10200	          }
10201	          return false;
10202	      }
10203	    },
10204
10205	    /**
10206	     * Check if the number of characters of field value exceed the threshold or not
10207	     *
10208	     * @param {jQuery} $field The field element
10209	     * @returns {Boolean}
10210	     */
10211	    _exceedThreshold: function($field) {
10212	      var field     = $field.attr('data-bv-field'),
10213	        threshold = this.options.fields[field].threshold || this.options.threshold;
10214	      if (!threshold) {
10215	        return true;
10216	      }
10217	      var cannotType = $.inArray($field.attr('type'), ['button', 'checkbox', 'file', 'hidden', 'image', 'radio', 'reset', 'submit']) !== -1;
10218	      return (cannotType || $field.val().length >= threshold);
10219	    },
10220
10221	    // ---
10222	    // Events
10223	    // ---
10224
10225	    /**
10226	     * The default handler of error.form.bv event.
10227	     * It will be called when there is a invalid field
10228	     *
10229	     * @param {jQuery.Event} e The jQuery event object
10230	     */
10231	    _onError: function(e) {
10232	      if (e.isDefaultPrevented()) {
10233	        return;
10234	      }
10235
10236	      if ('submitted' === this.options.live) {
10237	        // Enable live mode
10238	        this.options.live = 'enabled';
10239	        var that = this;
10240	        for (var field in this.options.fields) {
10241	          /*jshint -W083 */
10242	          (function(f) {
10243	            var fields  = that.getFieldElements(f);
10244	            if (fields.length) {
10245	              var type    = $(fields[0]).attr('type'),
10246	                event   = ('radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === $(fields[0]).get(0).tagName) ? 'change' : that._changeEvent,
10247	                trigger = that.options.fields[field].trigger || that.options.trigger || event,
10248	                events  = $.map(trigger.split(' '), function(item) {
10249	                  return item + '.live.bv';
10250	                }).join(' ');
10251
10252	              fields.off(events).on(events, function() {
10253	                if (that._exceedThreshold($(this))) {
10254	                  that.validateField($(this));
10255	                }
10256	              });
10257	            }
10258	          })(field);
10259	        }
10260	      }
10261
10262	      // Determined the first invalid field which will be focused on automatically
10263	      for (var i = 0; i < this.$invalidFields.length; i++) {
10264	        var $field    = this.$invalidFields.eq(i),
10265	          autoFocus = this._isOptionEnabled($field.attr('data-bv-field'), 'autoFocus');
10266	        if (autoFocus) {
10267	          // Activate the tab containing the field if exists
10268	          var $tabPane = $field.parents('.tab-pane'), tabId;
10269	          if ($tabPane && (tabId = $tabPane.attr('id'))) {
10270	            $('a[href="#' + tabId + '"][data-toggle="tab"]').tab('show');
10271	          }
10272
10273	          // Focus the field
10274	          $field.focus();
10275	          break;
10276	        }
10277	      }
10278	    },
10279
10280	    /**
10281	     * The default handler of success.form.bv event.
10282	     * It will be called when all the fields are valid
10283	     *
10284	     * @param {jQuery.Event} e The jQuery event object
10285	     */
10286	    _onSuccess: function(e) {
10287	      if (e.isDefaultPrevented()) {
10288	        return;
10289	      }
10290
10291	      // Submit the form
10292	      this.disableSubmitButtons(true).defaultSubmit();
10293	    },
10294
10295	    /**
10296	     * Called after validating a field element
10297	     *
10298	     * @param {jQuery} $field The field element
10299	     * @param {String} [validatorName] The validator name
10300	     */
10301	    _onFieldValidated: function($field, validatorName) {
10302	      var field         = $field.attr('data-bv-field'),
10303	        validators    = this.options.fields[field].validators,
10304	        counter       = {},
10305	        numValidators = 0,
10306	        data          = {
10307	          bv: this,
10308	          field: field,
10309	          element: $field,
10310	          validator: validatorName,
10311	          result: $field.data('bv.response.' + validatorName)
10312	        };
10313
10314	      // Trigger an event after given validator completes
10315	      if (validatorName) {
10316	        switch ($field.data('bv.result.' + validatorName)) {
10317	          case this.STATUS_INVALID:
10318	            $field.trigger($.Event(this.options.events.validatorError), data);
10319	            break;
10320	          case this.STATUS_VALID:
10321	            $field.trigger($.Event(this.options.events.validatorSuccess), data);
10322	            break;
10323	          default:
10324	            break;
10325	        }
10326	      }
10327
10328	      counter[this.STATUS_NOT_VALIDATED] = 0;
10329	      counter[this.STATUS_VALIDATING]    = 0;
10330	      counter[this.STATUS_INVALID]       = 0;
10331	      counter[this.STATUS_VALID]         = 0;
10332
10333	      for (var v in validators) {
10334	        if (validators[v].enabled === false) {
10335	          continue;
10336	        }
10337
10338	        numValidators++;
10339	        var result = $field.data('bv.result.' + v);
10340	        if (result) {
10341	          counter[result]++;
10342	        }
10343	      }
10344
10345	      if (counter[this.STATUS_VALID] === numValidators) {
10346	        // Remove from the list of invalid fields
10347	        this.$invalidFields = this.$invalidFields.not($field);
10348
10349	        $field.trigger($.Event(this.options.events.fieldSuccess), data);
10350	      }
10351	      // If all validators are completed and there is at least one validator which doesn't pass
10352	      else if ((counter[this.STATUS_NOT_VALIDATED] === 0 || !this._isOptionEnabled(field, 'verbose')) && counter[this.STATUS_VALIDATING] === 0 && counter[this.STATUS_INVALID] > 0) {
10353	        // Add to the list of invalid fields
10354	        this.$invalidFields = this.$invalidFields.add($field);
10355
10356	        $field.trigger($.Event(this.options.events.fieldError), data);
10357	      }
10358	    },
10359
10360	    /**
10361	     * Check whether or not a field option is enabled
10362	     *
10363	     * @param {String} field The field name
10364	     * @param {String} option The option name, "verbose", "autoFocus", for example
10365	     * @returns {Boolean}
10366	     */
10367	    _isOptionEnabled: function(field, option) {
10368	      if (this.options.fields[field] && (this.options.fields[field][option] === 'true' || this.options.fields[field][option] === true)) {
10369	        return true;
10370	      }
10371	      if (this.options.fields[field] && (this.options.fields[field][option] === 'false' || this.options.fields[field][option] === false)) {
10372	        return false;
10373	      }
10374	      return this.options[option] === 'true' || this.options[option] === true;
10375	    },
10376
10377	    // ---
10378	    // Public methods
10379	    // ---
10380
10381	    /**
10382	     * Retrieve the field elements by given name
10383	     *
10384	     * @param {String} field The field name
10385	     * @returns {null|jQuery[]}
10386	     */
10387	    getFieldElements: function(field) {
10388	      if (!this._cacheFields[field]) {
10389	        this._cacheFields[field] = (this.options.fields[field] && this.options.fields[field].selector) ?
10390	          $(this.options.fields[field].selector) :
10391	          this.$form.find('[name="' + field + '"]');
10392	      }
10393
10394	      return this._cacheFields[field];
10395	    },
10396
10397	    /**
10398	     * Get the field options
10399	     *
10400	     * @param {String|jQuery} [field] The field name or field element. If it is not set, the method returns the form options
10401	     * @param {String} [validator] The name of validator. It null, the method returns form options
10402	     * @param {String} [option] The option name
10403	     * @return {String|Object}
10404	     */
10405	    getOptions: function(field, validator, option) {
10406	      if (!field) {
10407	        return option ? this.options[option] : this.options;
10408	      }
10409	      if ('object' === typeof field) {
10410	        field = field.attr('data-bv-field');
10411	      }
10412	      if (!this.options.fields[field]) {
10413	        return null;
10414	      }
10415
10416	      var options = this.options.fields[field];
10417	      if (!validator) {
10418	        return option ? options[option] : options;
10419	      }
10420	      if (!options.validators || !options.validators[validator]) {
10421	        return null;
10422	      }
10423
10424	      return option ? options.validators[validator][option] : options.validators[validator];
10425	    },
10426
10427	    /**
10428	     * Disable/enable submit buttons
10429	     *
10430	     * @param {Boolean} disabled Can be true or false
10431	     * @returns {BootstrapValidator}
10432	     */
10433	    disableSubmitButtons: function(disabled) {
10434	      if (!disabled) {
10435	        this.$form.find(this.options.submitButtons).removeAttr('disabled');
10436	      } else if (this.options.live !== 'disabled') {
10437	        // Don't disable if the live validating mode is disabled
10438	        this.$form.find(this.options.submitButtons).attr('disabled', 'disabled');
10439	      }
10440
10441	      return this;
10442	    },
10443
10444	    /**
10445	     * Validate the form
10446	     *
10447	     * @returns {BootstrapValidator}
10448	     */
10449	    validate: function() {
10450	      if (!this.options.fields) {
10451	        return this;
10452	      }
10453	      this.disableSubmitButtons(true);
10454
10455	      this._submitIfValid = false;
10456	      for (var field in this.options.fields) {
10457	        this.validateField(field);
10458	      }
10459
10460	      this._submit();
10461	      this._submitIfValid = true;
10462
10463	      return this;
10464	    },
10465
10466	    /**
10467	     * Validate given field
10468	     *
10469	     * @param {String|jQuery} field The field name or field element
10470	     * @returns {BootstrapValidator}
10471	     */
10472	    validateField: function(field) {
10473	      var fields = $([]);
10474	      switch (typeof field) {
10475	        case 'object':
10476	          fields = field;
10477	          field  = field.attr('data-bv-field');
10478	          break;
10479	        case 'string':
10480	          fields = this.getFieldElements(field);
10481	          break;
10482	        default:
10483	          break;
10484	      }
10485
10486	      if (fields.length === 0 || !this.options.fields[field] || this.options.fields[field].enabled === false) {
10487	        return this;
10488	      }
10489
10490	      var that       = this,
10491	        type       = fields.attr('type'),
10492	        total      = ('radio' === type || 'checkbox' === type) ? 1 : fields.length,
10493	        updateAll  = ('radio' === type || 'checkbox' === type),
10494	        validators = this.options.fields[field].validators,
10495	        verbose    = this._isOptionEnabled(field, 'verbose'),
10496	        validatorName,
10497	        validateResult;
10498
10499	      for (var i = 0; i < total; i++) {
10500	        var $field = fields.eq(i);
10501	        if (this._isExcluded($field)) {
10502	          continue;
10503	        }
10504
10505	        var stop = false;
10506	        for (validatorName in validators) {
10507	          if ($field.data('bv.dfs.' + validatorName)) {
10508	            $field.data('bv.dfs.' + validatorName).reject();
10509	          }
10510	          if (stop) {
10511	            break;
10512	          }
10513
10514	          // Don't validate field if it is already done
10515	          var result = $field.data('bv.result.' + validatorName);
10516	          if (result === this.STATUS_VALID || result === this.STATUS_INVALID) {
10517	            this._onFieldValidated($field, validatorName);
10518	            continue;
10519	          } else if (validators[validatorName].enabled === false) {
10520	            this.updateStatus(updateAll ? field : $field, this.STATUS_VALID, validatorName);
10521	            continue;
10522	          }
10523
10524	          $field.data('bv.result.' + validatorName, this.STATUS_VALIDATING);
10525	          validateResult = $.fn.bootstrapValidator.validators[validatorName].validate(this, $field, validators[validatorName]);
10526
10527	          // validateResult can be a $.Deferred object ...
10528	          if ('object' === typeof validateResult && validateResult.resolve) {
10529	            this.updateStatus(updateAll ? field : $field, this.STATUS_VALIDATING, validatorName);
10530	            $field.data('bv.dfs.' + validatorName, validateResult);
10531	            /*jshint -W083 */
10532	            validateResult.done(function($f, v, response) {
10533	              // v is validator name
10534	              $f.removeData('bv.dfs.' + v).data('bv.response.' + v, response);
10535	              if (response.message) {
10536	                that.updateMessage($f, v, response.message);
10537	              }
10538
10539	              that.updateStatus(updateAll ? $f.attr('data-bv-field') : $f, response.valid ? that.STATUS_VALID : that.STATUS_INVALID, v);
10540
10541	              if (response.valid && that._submitIfValid === true) {
10542	                // If a remote validator returns true and the form is ready to submit, then do it
10543	                that._submit();
10544	              } else if (!response.valid && !verbose) {
10545	                stop = true;
10546	              }
10547	            });
10548	          }
10549	          // ... or object { valid: true/false, message: 'dynamic message' }
10550	          else if ('object' === typeof validateResult && validateResult.valid !== undefined && validateResult.message !== undefined) {
10551	            $field.data('bv.response.' + validatorName, validateResult);
10552	            this.updateMessage(updateAll ? field : $field, validatorName, validateResult.message);
10553	            this.updateStatus(updateAll ? field : $field, validateResult.valid ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
10554	            if (!validateResult.valid && !verbose) {
10555	              break;
10556	            }
10557	          }
10558	          // ... or a boolean value
10559	          else if ('boolean' === typeof validateResult) {
10560	            $field.data('bv.response.' + validatorName, validateResult);
10561	            this.updateStatus(updateAll ? field : $field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
10562	            if (!validateResult && !verbose) {
10563	              break;
10564	            }
10565	          }
10566	        }
10567	      }
10568
10569	      return this;
10570	    },
10571
10572	    /**
10573	     * Update the error message
10574	     *
10575	     * @param {String|jQuery} field The field name or field element
10576	     * @param {String} validator The validator name
10577	     * @param {String} message The message
10578	     * @returns {BootstrapValidator}
10579	     */
10580	    updateMessage: function(field, validator, message) {
10581	      var $fields = $([]);
10582	      switch (typeof field) {
10583	        case 'object':
10584	          $fields = field;
10585	          field   = field.attr('data-bv-field');
10586	          break;
10587	        case 'string':
10588	          $fields = this.getFieldElements(field);
10589	          break;
10590	        default:
10591	          break;
10592	      }
10593
10594	      $fields.each(function() {
10595	        $(this).data('bv.messages').find('.help-block[data-bv-validator="' + validator + '"][data-bv-for="' + field + '"]').html(message);
10596	      });
10597	    },
10598
10599	    /**
10600	     * Update all validating results of field
10601	     *
10602	     * @param {String|jQuery} field The field name or field element
10603	     * @param {String} status The status. Can be 'NOT_VALIDATED', 'VALIDATING', 'INVALID' or 'VALID'
10604	     * @param {String} [validatorName] The validator name. If null, the method updates validity result for all validators
10605	     * @returns {BootstrapValidator}
10606	     */
10607	    updateStatus: function(field, status, validatorName) {
10608	      var fields = $([]);
10609	      switch (typeof field) {
10610	        case 'object':
10611	          fields = field;
10612	          field  = field.attr('data-bv-field');
10613	          break;
10614	        case 'string':
10615	          fields = this.getFieldElements(field);
10616	          break;
10617	        default:
10618	          break;
10619	      }
10620
10621	      if (status === this.STATUS_NOT_VALIDATED) {
10622	        // Reset the flag
10623	        // To prevent the form from doing submit when a deferred validator returns true while typing
10624	        this._submitIfValid = false;
10625	      }
10626
10627	      var that  = this,
10628	        type  = fields.attr('type'),
10629	        group = this.options.fields[field].group || this.options.group,
10630	        total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
10631
10632	      for (var i = 0; i < total; i++) {
10633	        var $field       = fields.eq(i);
10634	        if (this._isExcluded($field)) {
10635	          continue;
10636	        }
10637
10638	        var $parent      = $field.parents(group),
10639	          $message     = $field.data('bv.messages'),
10640	          $allErrors   = $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]'),
10641	          $errors      = validatorName ? $allErrors.filter('[data-bv-validator="' + validatorName + '"]') : $allErrors,
10642	          $icon        = $field.data('bv.icon'),
10643	          container    = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container),
10644	          isValidField = null;
10645
10646	        // Update status
10647	        if (validatorName) {
10648	          $field.data('bv.result.' + validatorName, status);
10649	        } else {
10650	          for (var v in this.options.fields[field].validators) {
10651	            $field.data('bv.result.' + v, status);
10652	          }
10653	        }
10654
10655	        // Show/hide error elements and feedback icons
10656	        $errors.attr('data-bv-result', status);
10657
10658	        // Determine the tab containing the element
10659	        var $tabPane = $field.parents('.tab-pane'),
10660	          tabId, $tab;
10661	        if ($tabPane && (tabId = $tabPane.attr('id'))) {
10662	          $tab = $('a[href="#' + tabId + '"][data-toggle="tab"]').parent();
10663	        }
10664
10665	        switch (status) {
10666	          case this.STATUS_VALIDATING:
10667	            isValidField = null;
10668	            this.disableSubmitButtons(true);
10669	            $parent.removeClass('has-success').removeClass('has-error');
10670	            if ($icon) {
10671	              $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).addClass(this.options.feedbackIcons.validating).show();
10672	            }
10673	            if ($tab) {
10674	              $tab.removeClass('bv-tab-success').removeClass('bv-tab-error');
10675	            }
10676	            break;
10677
10678	          case this.STATUS_INVALID:
10679	            isValidField = false;
10680	            this.disableSubmitButtons(true);
10681	            $parent.removeClass('has-success').addClass('has-error');
10682	            if ($icon) {
10683	              $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.validating).addClass(this.options.feedbackIcons.invalid).show();
10684	            }
10685	            if ($tab) {
10686	              $tab.removeClass('bv-tab-success').addClass('bv-tab-error');
10687	            }
10688	            break;
10689
10690	          case this.STATUS_VALID:
10691	            // If the field is valid (passes all validators)
10692	            isValidField = ($allErrors.filter('[data-bv-result="' + this.STATUS_NOT_VALIDATED +'"]').length === 0) ?
10693	              ($allErrors.filter('[data-bv-result="' + this.STATUS_VALID +'"]').length === $allErrors.length) : // All validators are completed
10694	              null;                                                                                             // There are some validators that have not done
10695	            if (isValidField !== null) {
10696	              this.disableSubmitButtons(this.$submitButton ? !this.isValid() : !isValidField);
10697	              if ($icon) {
10698	                $icon
10699	                  .removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).removeClass(this.options.feedbackIcons.valid)
10700	                  .addClass(isValidField ? this.options.feedbackIcons.valid : this.options.feedbackIcons.invalid)
10701	                  .show();
10702	              }
10703	            }
10704
10705	            $parent.removeClass('has-error has-success').addClass(this.isValidContainer($parent) ? 'has-success' : 'has-error');
10706	            if ($tab) {
10707	              $tab.removeClass('bv-tab-success').removeClass('bv-tab-error').addClass(this.isValidContainer($tabPane) ? 'bv-tab-success' : 'bv-tab-error');
10708	            }
10709	            break;
10710
10711	          case this.STATUS_NOT_VALIDATED:
10712	          /* falls through */
10713	          default:
10714	            isValidField = null;
10715	            this.disableSubmitButtons(false);
10716	            $parent.removeClass('has-success').removeClass('has-error');
10717	            if ($icon) {
10718	              $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).hide();
10719	            }
10720	            if ($tab) {
10721	              $tab.removeClass('bv-tab-success').removeClass('bv-tab-error');
10722	            }
10723	            break;
10724	        }
10725
10726	        switch (true) {
10727	          // Only show the first error message if it is placed inside a tooltip ...
10728	          case ($icon && 'tooltip' === container):
10729	            if (isValidField === false) {
10730	              $icon.css('cursor', 'pointer').tooltip('destroy').tooltip({
10731	                container: 'body',
10732	                html: true,
10733	                placement: 'auto top',
10734	                title: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html()
10735	              });
10736	            }else {
10737	              $icon.css('cursor', '').tooltip('destroy');
10738	            }
10739	            break;
10740	          // ... or popover
10741	          case ($icon && 'popover' === container):
10742	            if (isValidField === false) {
10743	              $icon.css('cursor', 'pointer').popover('destroy').popover({
10744	                container: 'body',
10745	                content: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html(),
10746	                html: true,
10747	                placement: 'auto top',
10748	                trigger: 'hover click'
10749	              });
10750	            }else{
10751	              $icon.css('cursor', '').popover('destroy');
10752	            }
10753	            break;
10754	          default:
10755
10756	            ($errors[ (status === this.STATUS_INVALID) ? 'show' : 'hide'])();
10757
10758	            break;
10759	        }
10760
10761	        // Trigger an event
10762	        $field.trigger($.Event(this.options.events.fieldStatus), {
10763	          bv: this,
10764	          field: field,
10765	          element: $field,
10766	          status: status
10767	        });
10768	        this._onFieldValidated($field, validatorName);
10769	      }
10770
10771	      return this;
10772	    },
10773
10774	    /**
10775	     * Check the form validity
10776	     *
10777	     * @returns {Boolean}
10778	     */
10779	    isValid: function() {
10780	      for (var field in this.options.fields) {
10781	        if (!this.isValidField(field)) {
10782	          return false;
10783	        }
10784	      }
10785
10786	      return true;
10787	    },
10788
10789	    /**
10790	     * Check if the field is valid or not
10791	     *
10792	     * @param {String|jQuery} field The field name or field element
10793	     * @returns {Boolean}
10794	     */
10795	    isValidField: function(field) {
10796	      var fields = $([]);
10797	      switch (typeof field) {
10798	        case 'object':
10799	          fields = field;
10800	          field  = field.attr('data-bv-field');
10801	          break;
10802	        case 'string':
10803	          fields = this.getFieldElements(field);
10804	          break;
10805	        default:
10806	          break;
10807	      }
10808	      if (fields.length === 0 || !this.options.fields[field] || this.options.fields[field].enabled === false) {
10809	        return true;
10810	      }
10811
10812	      var type  = fields.attr('type'),
10813	        total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length,
10814	        $field, validatorName, status;
10815	      for (var i = 0; i < total; i++) {
10816	        $field = fields.eq(i);
10817	        if (this._isExcluded($field)) {
10818	          continue;
10819	        }
10820
10821	        for (validatorName in this.options.fields[field].validators) {
10822	          if (this.options.fields[field].validators[validatorName].enabled === false) {
10823	            continue;
10824	          }
10825
10826	          status = $field.data('bv.result.' + validatorName);
10827	          if (status !== this.STATUS_VALID) {
10828	            return false;
10829	          }
10830	        }
10831	      }
10832
10833	      return true;
10834	    },
10835
10836	    /**
10837	     * Check if all fields inside a given container are valid.
10838	     * It's useful when working with a wizard-like such as tab, collapse
10839	     *
10840	     * @param {String|jQuery} container The container selector or element
10841	     * @returns {Boolean}
10842	     */
10843	    isValidContainer: function(container) {
10844	      var that       = this,
10845	        map        = {},
10846	        $container = ('string' === typeof container) ? $(container) : container;
10847	      if ($container.length === 0) {
10848	        return true;
10849	      }
10850
10851	      $container.find('[data-bv-field]').each(function() {
10852	        var $field = $(this),
10853	          field  = $field.attr('data-bv-field');
10854	        if (!that._isExcluded($field) && !map[field]) {
10855	          map[field] = $field;
10856	        }
10857	      });
10858
10859	      for (var field in map) {
10860	        var $f = map[field];
10861	        if ($f.data('bv.messages')
10862	            .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]')
10863	            .filter('[data-bv-result="' + this.STATUS_INVALID +'"]')
10864	            .length > 0)
10865	        {
10866	          return false;
10867	        }
10868	      }
10869
10870	      return true;
10871	    },
10872
10873	    /**
10874	     * Submit the form using default submission.
10875	     * It also does not perform any validations when submitting the form
10876	     */
10877	    defaultSubmit: function() {
10878	      if (this.$submitButton) {
10879	        // Create hidden input to send the submit buttons
10880	        $('<input/>')
10881	          .attr('type', 'hidden')
10882	          .attr('data-bv-submit-hidden', '')
10883	          .attr('name', this.$submitButton.attr('name'))
10884	          .val(this.$submitButton.val())
10885	          .appendTo(this.$form);
10886	      }
10887
10888	      // Submit form
10889	      this.$form.off('submit.bv').submit();
10890	    },
10891
10892	    // ---
10893	    // Useful APIs which aren't used internally
10894	    // ---
10895
10896	    /**
10897	     * Get the list of invalid fields
10898	     *
10899	     * @returns {jQuery[]}
10900	     */
10901	    getInvalidFields: function() {
10902	      return this.$invalidFields;
10903	    },
10904
10905	    /**
10906	     * Returns the clicked submit button
10907	     *
10908	     * @returns {jQuery}
10909	     */
10910	    getSubmitButton: function() {
10911	      return this.$submitButton;
10912	    },
10913
10914	    /**
10915	     * Get the error messages
10916	     *
10917	     * @param {String|jQuery} [field] The field name or field element
10918	     * If the field is not defined, the method returns all error messages of all fields
10919	     * @param {String} [validator] The name of validator
10920	     * If the validator is not defined, the method returns error messages of all validators
10921	     * @returns {String[]}
10922	     */
10923	    getMessages: function(field, validator) {
10924	      var that     = this,
10925	        messages = [],
10926	        $fields  = $([]);
10927
10928	      switch (true) {
10929	        case (field && 'object' === typeof field):
10930	          $fields = field;
10931	          break;
10932	        case (field && 'string' === typeof field):
10933	          var f = this.getFieldElements(field);
10934	          if (f.length > 0) {
10935	            var type = f.attr('type');
10936	            $fields = ('radio' === type || 'checkbox' === type) ? f.eq(0) : f;
10937	          }
10938	          break;
10939	        default:
10940	          $fields = this.$invalidFields;
10941	          break;
10942	      }
10943
10944	      var filter = validator ? '[data-bv-validator="' + validator + '"]' : '';
10945	      $fields.each(function() {
10946	        messages = messages.concat(
10947	          $(this)
10948	            .data('bv.messages')
10949	            .find('.help-block[data-bv-for="' + $(this).attr('data-bv-field') + '"][data-bv-result="' + that.STATUS_INVALID + '"]' + filter)
10950	            .map(function() {
10951	              var v = $(this).attr('data-bv-validator'),
10952	                f = $(this).attr('data-bv-for');
10953	              return (that.options.fields[f].validators[v].enabled === false) ? '' : $(this).html();
10954	            })
10955	            .get()
10956	        );
10957	      });
10958
10959	      return messages;
10960	    },
10961
10962	    /**
10963	     * Update the option of a specific validator
10964	     *
10965	     * @param {String|jQuery} field The field name or field element
10966	     * @param {String} validator The validator name
10967	     * @param {String} option The option name
10968	     * @param {String} value The value to set
10969	     * @returns {BootstrapValidator}
10970	     */
10971	    updateOption: function(field, validator, option, value) {
10972	      if ('object' === typeof field) {
10973	        field = field.attr('data-bv-field');
10974	      }
10975	      if (this.options.fields[field] && this.options.fields[field].validators[validator]) {
10976	        this.options.fields[field].validators[validator][option] = value;
10977	        this.updateStatus(field, this.STATUS_NOT_VALIDATED, validator);
10978	      }
10979
10980	      return this;
10981	    },
10982
10983	    /**
10984	     * Add a new field
10985	     *
10986	     * @param {String|jQuery} field The field name or field element
10987	     * @param {Object} [options] The validator rules
10988	     * @returns {BootstrapValidator}
10989	     */
10990	    addField: function(field, options) {
10991	      var fields = $([]);
10992	      switch (typeof field) {
10993	        case 'object':
10994	          fields = field;
10995	          field  = field.attr('data-bv-field') || field.attr('name');
10996	          break;
10997	        case 'string':
10998	          delete this._cacheFields[field];
10999	          fields = this.getFieldElements(field);
11000	          break;
11001	        default:
11002	          break;
11003	      }
11004
11005	      fields.attr('data-bv-field', field);
11006
11007	      var type  = fields.attr('type'),
11008	        total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
11009
11010	      for (var i = 0; i < total; i++) {
11011	        var $field = fields.eq(i);
11012
11013	        // Try to parse the options from HTML attributes
11014	        var opts = this._parseOptions($field);
11015	        opts = (opts === null) ? options : $.extend(true, options, opts);
11016
11017	        this.options.fields[field] = $.extend(true, this.options.fields[field], opts);
11018
11019	        // Update the cache
11020	        this._cacheFields[field] = this._cacheFields[field] ? this._cacheFields[field].add($field) : $field;
11021
11022	        // Init the element
11023	        this._initField(('checkbox' === type || 'radio' === type) ? field : $field);
11024	      }
11025
11026	      this.disableSubmitButtons(false);
11027	      // Trigger an event
11028	      this.$form.trigger($.Event(this.options.events.fieldAdded), {
11029	        field: field,
11030	        element: fields,
11031	        options: this.options.fields[field]
11032	      });
11033
11034	      return this;
11035	    },
11036
11037	    /**
11038	     * Remove a given field
11039	     *
11040	     * @param {String|jQuery} field The field name or field element
11041	     * @returns {BootstrapValidator}
11042	     */
11043	    removeField: function(field) {
11044	      var fields = $([]);
11045	      switch (typeof field) {
11046	        case 'object':
11047	          fields = field;
11048	          field  = field.attr('data-bv-field') || field.attr('name');
11049	          fields.attr('data-bv-field', field);
11050	          break;
11051	        case 'string':
11052	          fields = this.getFieldElements(field);
11053	          break;
11054	        default:
11055	          break;
11056	      }
11057
11058	      if (fields.length === 0) {
11059	        return this;
11060	      }
11061
11062	      var type  = fields.attr('type'),
11063	        total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
11064
11065	      for (var i = 0; i < total; i++) {
11066	        var $field = fields.eq(i);
11067
11068	        // Remove from the list of invalid fields
11069	        this.$invalidFields = this.$invalidFields.not($field);
11070
11071	        // Update the cache
11072	        this._cacheFields[field] = this._cacheFields[field].not($field);
11073	      }
11074
11075	      if (!this._cacheFields[field] || this._cacheFields[field].length === 0) {
11076	        delete this.options.fields[field];
11077	      }
11078	      if ('checkbox' === type || 'radio' === type) {
11079	        this._initField(field);
11080	      }
11081
11082	      this.disableSubmitButtons(false);
11083	      // Trigger an event
11084	      this.$form.trigger($.Event(this.options.events.fieldRemoved), {
11085	        field: field,
11086	        element: fields
11087	      });
11088
11089	      return this;
11090	    },
11091
11092	    /**
11093	     * Reset given field
11094	     *
11095	     * @param {String|jQuery} field The field name or field element
11096	     * @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox)
11097	     * @returns {BootstrapValidator}
11098	     */
11099	    resetField: function(field, resetValue) {
11100	      var $fields = $([]);
11101	      switch (typeof field) {
11102	        case 'object':
11103	          $fields = field;
11104	          field   = field.attr('data-bv-field');
11105	          break;
11106	        case 'string':
11107	          $fields = this.getFieldElements(field);
11108	          break;
11109	        default:
11110	          break;
11111	      }
11112
11113	      var total = $fields.length;
11114	      if (this.options.fields[field]) {
11115	        for (var i = 0; i < total; i++) {
11116	          for (var validator in this.options.fields[field].validators) {
11117	            $fields.eq(i).removeData('bv.dfs.' + validator);
11118	          }
11119	        }
11120	      }
11121
11122	      // Mark field as not validated yet
11123	      this.updateStatus(field, this.STATUS_NOT_VALIDATED);
11124
11125	      if (resetValue) {
11126	        var type = $fields.attr('type');
11127	        if ('radio' === type || 'checkbox' === type) {
11128	          $fields.removeAttr('checked').removeAttr('selected');
11129	        }else{
11130	          $fields.val('');
11131	        }
11132	      }
11133
11134	      return this;
11135	    },
11136
11137	    /**
11138	     * Reset the form
11139	     *
11140	     * @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox)
11141	     * @returns {BootstrapValidator}
11142	     */
11143	    resetForm: function(resetValue) {
11144	      for (var field in this.options.fields) {
11145	        this.resetField(field, resetValue);
11146	      }
11147
11148	      this.$invalidFields = $([]);
11149	      this.$submitButton  = null;
11150
11151	      // Enable submit buttons
11152	      this.disableSubmitButtons(false);
11153
11154	      return this;
11155	    },
11156
11157	    /**
11158	     * Revalidate given field
11159	     * It's used when you need to revalidate the field which its value is updated by other plugin
11160	     *
11161	     * @param {String|jQuery} field The field name of field element
11162	     * @returns {BootstrapValidator}
11163	     */
11164	    revalidateField: function(field) {
11165	      this.updateStatus(field, this.STATUS_NOT_VALIDATED)
11166	        .validateField(field);
11167
11168	      return this;
11169	    },
11170
11171	    /**
11172	     * Enable/Disable all validators to given field
11173	     *
11174	     * @param {String} field The field name
11175	     * @param {Boolean} enabled Enable/Disable field validators
11176	     * @param {String} [validatorName] The validator name. If null, all validators will be enabled/disabled
11177	     * @returns {BootstrapValidator}
11178	     */
11179	    enableFieldValidators: function(field, enabled, validatorName) {
11180	      var validators = this.options.fields[field].validators;
11181
11182	      // Enable/disable particular validator
11183	      if (validatorName &&
11184	        validators &&
11185	        validators[validatorName] &&
11186	        validators[validatorName].enabled !== enabled)
11187	      {
11188	        this.options.fields[field].validators[validatorName].enabled = enabled;
11189	        this.updateStatus(field, this.STATUS_NOT_VALIDATED, validatorName);
11190	      }
11191	      // Enable/disable all validators
11192	      else if (!validatorName && this.options.fields[field].enabled !== enabled) {
11193	        this.options.fields[field].enabled = enabled;
11194	        for (var v in validators) {
11195	          this.enableFieldValidators(field, enabled, v);
11196	        }
11197	      }
11198
11199	      return this;
11200	    },
11201
11202	    /**
11203	     * Some validators have option which its value is dynamic.
11204	     * For example, the zipCode validator has the country option which might be changed dynamically by a select element.
11205	     *
11206	     * @param {jQuery|String} field The field name or element
11207	     * @param {String|Function} option The option which can be determined by:
11208	     * - a string
11209	     * - name of field which defines the value
11210	     * - name of function which returns the value
11211	     * - a function returns the value
11212	     *
11213	     * The callback function has the format of
11214	     *      callback: function(value, validator, $field) {
11215	         *          // value is the value of field
11216	         *          // validator is the BootstrapValidator instance
11217	         *          // $field is the field element
11218	         *      }
11219	     *
11220	     * @returns {String}
11221	     */
11222	    getDynamicOption: function(field, option) {
11223	      var $field = ('string' === typeof field) ? this.getFieldElements(field) : field,
11224	        value  = $field.val();
11225
11226	      // Option can be determined by
11227	      // ... a function
11228	      if ('function' === typeof option) {
11229	        return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]);
11230	      }
11231	      // ... value of other field
11232	      else if ('string' === typeof option) {
11233	        var $f = this.getFieldElements(option);
11234	        if ($f.length) {
11235	          return $f.val();
11236	        }
11237	        // ... return value of callback
11238	        else {
11239	          return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]) || option;
11240	        }
11241	      }
11242
11243	      return null;
11244	    },
11245
11246	    /**
11247	     * Destroy the plugin
11248	     * It will remove all error messages, feedback icons and turn off the events
11249	     */
11250	    destroy: function() {
11251	      var field, fields, $field, validator, $icon, group;
11252	      for (field in this.options.fields) {
11253	        fields    = this.getFieldElements(field);
11254	        group     = this.options.fields[field].group || this.options.group;
11255	        for (var i = 0; i < fields.length; i++) {
11256	          $field = fields.eq(i);
11257	          $field
11258	            // Remove all error messages
11259	            .data('bv.messages')
11260	            .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove().end()
11261	            .end()
11262	            .removeData('bv.messages')
11263	            // Remove feedback classes
11264	            .parents(group)
11265	            .removeClass('has-feedback has-error has-success')
11266	            .end()
11267	            // Turn off events
11268	            .off('.bv')
11269	            .removeAttr('data-bv-field');
11270
11271	          // Remove feedback icons, tooltip/popover container
11272	          $icon = $field.data('bv.icon');
11273	          if ($icon) {
11274	            var container = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container);
11275	            switch (container) {
11276	              case 'tooltip':
11277	                $icon.tooltip('destroy').remove();
11278	                break;
11279	              case 'popover':
11280	                $icon.popover('destroy').remove();
11281	                break;
11282	              default:
11283	                $icon.remove();
11284	                break;
11285	            }
11286	          }
11287	          $field.removeData('bv.icon');
11288
11289	          for (validator in this.options.fields[field].validators) {
11290	            if ($field.data('bv.dfs.' + validator)) {
11291	              $field.data('bv.dfs.' + validator).reject();
11292	            }
11293	            $field.removeData('bv.result.' + validator)
11294	              .removeData('bv.response.' + validator)
11295	              .removeData('bv.dfs.' + validator);
11296
11297	            // Destroy the validator
11298	            if ('function' === typeof $.fn.bootstrapValidator.validators[validator].destroy) {
11299	              $.fn.bootstrapValidator.validators[validator].destroy(this, $field, this.options.fields[field].validators[validator]);
11300	            }
11301	          }
11302	        }
11303	      }
11304
11305	      this.disableSubmitButtons(false);   // Enable submit buttons
11306	      this.$hiddenButton.remove();        // Remove the hidden button
11307
11308	      this.$form
11309	        .removeClass(this.options.elementClass)
11310	        .off('.bv')
11311	        .removeData('bootstrapValidator')
11312	        // Remove generated hidden elements
11313	        .find('[data-bv-submit-hidden]').remove().end()
11314	        .find('[type="submit"]').off('click.bv');
11315	    }
11316	  };
11317
11318	  // Plugin definition
11319	  $.fn.bootstrapValidator = function(option) {
11320	    var params = arguments;
11321	    return this.each(function() {
11322	      var $this   = $(this),
11323	        data    = $this.data('bootstrapValidator'),
11324	        options = 'object' === typeof option && option;
11325	      if (!data) {
11326	        data = new BootstrapValidator(this, options);
11327	        $this.data('bootstrapValidator', data);
11328	      }
11329
11330	      // Allow to call plugin method
11331	      if ('string' === typeof option) {
11332	        data[option].apply(data, Array.prototype.slice.call(params, 1));
11333	      }
11334	    });
11335	  };
11336
11337	  // The default options
11338	  // Sorted in alphabetical order
11339	  $.fn.bootstrapValidator.DEFAULT_OPTIONS = {
11340	    // The first invalid field will be focused automatically
11341	    autoFocus: true,
11342
11343	    //The error messages container. It can be:
11344	    // - 'tooltip' if you want to use Bootstrap tooltip to show error messages
11345	    // - 'popover' if you want to use Bootstrap popover to show error messages
11346	    // - a CSS selector indicating the container
11347	    // In the first two cases, since the tooltip/popover should be small enough, the plugin only shows only one error message
11348	    // You also can define the message container for particular field
11349	    container: null,
11350
11351	    // The form CSS class
11352	    elementClass: 'bv-form',
11353
11354	    // Use custom event name to avoid window.onerror being invoked by jQuery
11355	    // See https://github.com/nghuuphuoc/bootstrapvalidator/issues/630
11356	    events: {
11357	      formInit: 'init.form.bv',
11358	      formError: 'error.form.bv',
11359	      formSuccess: 'success.form.bv',
11360	      fieldAdded: 'added.field.bv',
11361	      fieldRemoved: 'removed.field.bv',
11362	      fieldInit: 'init.field.bv',
11363	      fieldError: 'error.field.bv',
11364	      fieldSuccess: 'success.field.bv',
11365	      fieldStatus: 'status.field.bv',
11366	      validatorError: 'error.validator.bv',
11367	      validatorSuccess: 'success.validator.bv'
11368	    },
11369
11370	    // Indicate fields which won't be validated
11371	    // By default, the plugin will not validate the following kind of fields:
11372	    // - disabled
11373	    // - hidden
11374	    // - invisible
11375	    //
11376	    // The setting consists of jQuery filters. Accept 3 formats:
11377	    // - A string. Use a comma to separate filter
11378	    // - An array. Each element is a filter
11379	    // - An array. Each element can be a callback function
11380	    //      function($field, validator) {
11381	    //          $field is jQuery object representing the field element
11382	    //          validator is the BootstrapValidator instance
11383	    //          return true or false;
11384	    //      }
11385	    //
11386	    // The 3 following settings are equivalent:
11387	    //
11388	    // 1) ':disabled, :hidden, :not(:visible)'
11389	    // 2) [':disabled', ':hidden', ':not(:visible)']
11390	    // 3) [':disabled', ':hidden', function($field) {
11391	    //        return !$field.is(':visible');
11392	    //    }]
11393	    excluded: [':disabled', ':hidden', ':not(:visible)'],
11394
11395	    // Shows ok/error/loading icons based on the field validity.
11396	    // This feature requires Bootstrap v3.1.0 or later (http://getbootstrap.com/css/#forms-control-validation).
11397	    // Since Bootstrap doesn't provide any methods to know its version, this option cannot be on/off automatically.
11398	    // In other word, to use this feature you have to upgrade your Bootstrap to v3.1.0 or later.
11399	    //
11400	    // Examples:
11401	    // - Use Glyphicons icons:
11402	    //  feedbackIcons: {
11403	    //      valid: 'glyphicon glyphicon-ok',
11404	    //      invalid: 'glyphicon glyphicon-remove',
11405	    //      validating: 'glyphicon glyphicon-refresh'
11406	    //  }
11407	    // - Use FontAwesome icons:
11408	    //  feedbackIcons: {
11409	    //      valid: 'fa fa-check',
11410	    //      invalid: 'fa fa-times',
11411	    //      validating: 'fa fa-refresh'
11412	    //  }
11413	    feedbackIcons: {
11414	      valid:      null,
11415	      invalid:    null,
11416	      validating: null
11417	    },
11418
11419	    // Map the field name with validator rules
11420	    fields: null,
11421
11422	    // The CSS selector for indicating the element consists the field
11423	    // By default, each field is placed inside the <div class="form-group"></div>
11424	    // You should adjust this option if your form group consists of many fields which not all of them need to be validated
11425	    group: '.form-group',
11426
11427	    // Live validating option
11428	    // Can be one of 3 values:
11429	    // - enabled: The plugin validates fields as soon as they are changed
11430	    // - disabled: Disable the live validating. The error messages are only shown after the form is submitted
11431	    // - submitted: The live validating is enabled after the form is submitted
11432	    live: 'enabled',
11433
11434	    // Default invalid message
11435	    message: 'This value is not valid',
11436
11437	    // The submit buttons selector
11438	    // These buttons will be disabled to prevent the valid form from multiple submissions
11439	    submitButtons: '[type="submit"]',
11440
11441	    // The field will not be live validated if its length is less than this number of characters
11442	    threshold: null,
11443
11444	    // Whether to be verbose when validating a field or not.
11445	    // Possible values:
11446	    // - true:  when a field has multiple validators, all of them will be checked, and respectively - if errors occur in
11447	    //          multiple validators, all of them will be displayed to the user
11448	    // - false: when a field has multiple validators, validation for this field will be terminated upon the first encountered error.
11449	    //          Thus, only the very first error message related to this field will be displayed to the user
vendor: 4,102 bytes, lines 11450-11586
11450	    verbose: true
11451	  };
11452
11453	  // Available validators
11454	  $.fn.bootstrapValidator.validators  = {};
11455
11456	  // i18n
11457	  $.fn.bootstrapValidator.i18n        = {};
11458
11459	  $.fn.bootstrapValidator.Constructor = BootstrapValidator;
11460
11461	  // Helper methods, which can be used in validator class
11462	  $.fn.bootstrapValidator.helpers = {
11463	    /**
11464	     * Execute a callback function
11465	     *
11466	     * @param {String|Function} functionName Can be
11467	     * - name of global function
11468	     * - name of namespace function (such as A.B.C)
11469	     * - a function
11470	     * @param {Array} args The callback arguments
11471	     */
11472	    call: function(functionName, args) {
11473	      if ('function' === typeof functionName) {
11474	        return functionName.apply(this, args);
11475	      } else if ('string' === typeof functionName) {
11476	        if ('()' === functionName.substring(functionName.length - 2)) {
11477	          functionName = functionName.substring(0, functionName.length - 2);
11478	        }
11479	        var ns      = functionName.split('.'),
11480	          func    = ns.pop(),
11481	          context = window;
11482	        for (var i = 0; i < ns.length; i++) {
11483	          context = context[ns[i]];
11484	        }
11485
11486	        return (typeof context[func] === 'undefined') ? null : context[func].apply(this, args);
11487	      }
11488	    },
11489
11490	    /**
11491	     * Format a string
11492	     * It's used to format the error message
11493	     * format('The field must between %s and %s', [10, 20]) = 'The field must between 10 and 20'
11494	     *
11495	     * @param {String} message
11496	     * @param {Array} parameters
11497	     * @returns {String}
11498	     */
11499	    format: function(message, parameters) {
11500	      if (!$.isArray(parameters)) {
11501	        parameters = [parameters];
11502	      }
11503
11504	      for (var i in parameters) {
11505	        message = message.replace('%s', parameters[i]);
11506	      }
11507
11508	      return message;
11509	    },
11510
11511	    /**
11512	     * Validate a date
11513	     *
11514	     * @param {Number} year The full year in 4 digits
11515	     * @param {Number} month The month number
11516	     * @param {Number} day The day number
11517	     * @param {Boolean} [notInFuture] If true, the date must not be in the future
11518	     * @returns {Boolean}
11519	     */
11520	    date: function(year, month, day, notInFuture) {
11521	      if (isNaN(year) || isNaN(month) || isNaN(day)) {
11522	        return false;
11523	      }
11524	      if (day.length > 2 || month.length > 2 || year.length > 4) {
11525	        return false;
11526	      }
11527
11528	      day   = parseInt(day, 10);
11529	      month = parseInt(month, 10);
11530	      year  = parseInt(year, 10);
11531
11532	      if (year < 1000 || year > 9999 || month <= 0 || month > 12) {
11533	        return false;
11534	      }
11535	      var numDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
11536	      // Update the number of days in Feb of leap year
11537	      if (year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)) {
11538	        numDays[1] = 29;
11539	      }
11540
11541	      // Check the day
11542	      if (day <= 0 || day > numDays[month - 1]) {
11543	        return false;
11544	      }
11545
11546	      if (notInFuture === true) {
11547	        var currentDate  = new Date(),
11548	          currentYear  = currentDate.getFullYear(),
11549	          currentMonth = currentDate.getMonth(),
11550	          currentDay   = currentDate.getDate();
11551	        return (year < currentYear ||
11552	        (year === currentYear && month - 1 < currentMonth) ||
11553	        (year === currentYear && month - 1 === currentMonth && day < currentDay));
11554	      }
11555
11556	      return true;
11557	    },
11558
11559	    /**
11560	     * Implement Luhn validation algorithm
11561	     * Credit to https://gist.github.com/ShirtlessKirk/2134376
11562	     *
11563	     * @see http://en.wikipedia.org/wiki/Luhn
11564	     * @param {String} value
11565	     * @returns {Boolean}
11566	     */
11567	    luhn: function(value) {
11568	      var length  = value.length,
11569	        mul     = 0,
11570	        prodArr = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]],
11571	        sum     = 0;
11572
11573	      while (length--) {
11574	        sum += prodArr[mul][parseInt(value.charAt(length), 10)];
11575	        mul ^= 1;
11576	      }
11577
11578	      return (sum % 10 === 0 && sum > 0);
11579	    },
11580
11581	    /**
11582	     * Implement modulus 11, 10 (ISO 7064) algorithm
11583	     *
11584	     * @param {String} value
11585	     * @returns {Boolean}
11586	     */
11587	    mod11And10: function(value) {
11588	      var check  = 5,
11589	        length = value.length;
11590	      for (var i = 0; i < length; i++) {
11591	        check = (((check || 10) * 2) % 11 + parseInt(value.charAt(i), 10)) % 10;
11592	      }
11593	      return (check === 1);
11594	    },
11595
11596	    /**
11597	     * Implements Mod 37, 36 (ISO 7064) algorithm
11598	     * Usages:
11599	     * mod37And36('A12425GABC1234002M')
11600	     * mod37And36('002006673085', '0123456789')
11601	     *
11602	     * @param {String} value
11603	     * @param {String} [alphabet]
11604	     * @returns {Boolean}
11605	     */
11606	    mod37And36: function(value, alphabet) {
11607	      alphabet = alphabet || '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
11608	      var modulus = alphabet.length,
11609	        length  = value.length,
11610	        check   = Math.floor(modulus / 2);
11611	      for (var i = 0; i < length; i++) {
11612	        check = (((check || modulus) * 2) % (modulus + 1) + alphabet.indexOf(value.charAt(i))) % modulus;
11613	      }
11614	      return (check === 1);
11615	    }
11616	  };
11617
11618	  // init:
11619	  $(document).on('bv:init', function(e){
11620	    var $formInstances = $('[data-bv]');
11621	    $formInstances.each(function (ind, obj) {
11622	      var $bvForm = $(obj).bootstrapValidator();
11623	    });
11624	  });
11625
11626	  // if we need to validate the form via ajax:
11627	  $(document).on('click', 'form [data-bv-submit]', function(e) {
11628	    $(e.currentTarget).closest('form').trigger('submit.bv');
11629	  });
11630
11631	// Debug form:
11632	  /*  $(document).on('error.field.bv',function(e){
11633	   console.log('Error Field');
11634	   console.debug(e);
11635	   });
11636	   $(document).on('init.field.bv',function(e){
11637	   console.log('init Field');
11638	   console.debug(e);
11639	   });
11640	   $(document).on('success.field.bv',function(e){
11641	   console.log('Success Field');
11642	   console.debug(e);
11643	   });
11644	   $(document).on('status.field.bv',function(e){
11645	   console.log('Status Field');
11646	   console.debug(e);
11647	   });
11648	   $(document).on('error.validator.bv',function(e, data){
11649	   console.log('Error Validator ' + data.validator);
11650	   console.debug(e);
11651	   });
11652	   $(document).on('init.form.bv',function(e){
11653	   console.log('Form Init');
11654	   console.debug(e);
11655	   });
11656	   $(document).on('error.form.bv',function(e){
11657	   console.log('Form Error');
11658	   console.debug(e);
11659	   });
11660	   $(document).on('success.form.bv',function(e){
11661	   console.log('Form Success');
11662	   console.debug(e);
11663	   });
11664	   $(document).on('added.field.bv',function(e){
11665	   console.log('Added Field');
11666	   console.debug(e);
11667	   });
11668	   $(document).on('removed.field.bv',function(e){
11669	   console.log('Removed Field');
11670	   console.debug(e);
11671	   });*/
11672
11673
11674
11675	}(window.jQuery));
11676
11677
11678/***/ }),
11679
11680/***/ 333:
11681/***/ (function(module, exports) {
11682
11683	/**
11684	 * Smart Replace
11685	 *
11686	 * Adds some variables to the global scope and make them available for replacement.
11687	 *
11688	 * usage:
11689	 * var mreplacements = {};
11690	 * mreplacements.test = 'a test';
11691	 * mstring = "this is {{test}}";
11692	 * res = $.smartReplace.replace(mstring, mreplacements); // this is a test
11693	 *
11694	 * usage 2:
11695	 * add data-autoreplace="objReference" to your html element.
11696	 * and the plugin will use the obj in $.smartReplace.objReference to replace the contents of the element.
11697	 *
11698	 **/
11699
11700
11701	$(function (){
11702	  $.smartReplace = {
11703	    vars: {},
11704	    replace: function (pattern, replacements) {
11705	      // function argument overrides global variable:
11706	      var reps = $.extend({}, $.smartReplace.vars, replacements);
11707
11708	      if (pattern !== undefined && reps !== undefined) {
11709	        pattern = pattern.replace(/<%(.[a-zA-Z0-9_\-\[\]]{1,35})%>/g, function (index, varName) {
11710
11711	          if (reps[varName] !== undefined) {
11712	            return reps[varName];
11713	          } else {
11714	            return '{{' + varName + '}}';
11715	          }
11716
11717	        });
11718	      }
11719	      return pattern;
11720	    },
11721	    bulkReplace: function (string, replacements){
11722	      if (string !== undefined && replacements !== undefined){
11723	        for (var rep in replacements){
11724
11725	          if (replacements[rep].regex === true && typeof(replacements[rep].replace) === 'function'){
11726	            var r = new RegExp(replacements[rep].find, "g");
11727	            string = string.replace(r, replacements[rep].replace);
11728	          }else {
11729	            string = string.replace(replacements[rep].find, replacements[rep].replace);
11730	          }
11731	        }
11732	        return string;
11733	      }
11734	    },
11735	    edmundsReplacements: [
11736	      {find: 'AWD', replace: 'All Wheel Drive'},
11737	      {find: '4WD', replace: 'Four-wheel Drive'},
11738	      {find: 'SUV', replace: 'Sport Utility Vehicle'},
11739	      {find: 'WB', replace: 'Wheel Base'},
11740	      {find: 'HR', replace: 'High Roof'},
11741	      {find: 'w/', replace: 'With '},
11742	      {find: 'Ext Van', replace: 'Extended Van'},
11743	      {find: 'Pkg', replace: 'Package'},
11744	      {find: 'CVT', replace: 'Continuously Variable Transmission'},
11745	      {find: 'GTS', replace: 'Gran Turismo'},
11746	      {find: '([0-9]{2,3}) ft. SB', replace: function(index, match){
11747	        return match + ' feet Short Box';
11748	      }, regex: true},
11749	      {find: '([0-9]{1})dr', replace: function(index, match){
11750	        return match + ' Doors';
11751	      }, regex: true},
11752	      {find: '([0-9.]{1,3})L', replace: function(index, match){
11753	        return match + ' Liters';
11754	      }, regex: true},
11755	      {find: '([0-9]{1})M', replace: function(index, match){
11756	        return match + '-speed manual transmission';
11757	      }, regex: true},
11758	      {find: '([0-9]{1})A', replace: function(index, match){
11759	        return match + '-speed automatic transmission';
11760	      }, regex: true},
11761	      {find: '([0-9]{1,2})cyl',replace: function(index, match){
11762	        return match + ' Cylinders';
11763	      }, regex: true},
11764	      {find: 'Turbodiesel', replace: 'Turbo Diesel'}
11765	    ]
11766	  };
11767
11768	  $(document).on('change', 'input, select', function(e){
11769	    var id = $(e.target).prop('name');
11770	    if (id !== undefined){
11771	      $.smartReplace.vars[id]=$(e.target).val();
11772	    }else{
11773	      console.warn('Not a valid input name found!'+ e.currentTarget.toString());
11774	    }
11775	  });
11776
11777	  // update action before send forms:
11778	  $(document).on('submit', 'form', function(e){
11779	    var action = $.smartReplace.replace( $(e.target).prop('action'), {} );
11780	    $(e.target).prop('action', action);
11781	  });
11782
11783	  $('[data-smartreplace]').each(function(ind, obj){
11784	    var oldText = $(obj).text();
11785	    var replacements = $(obj).data('smartreplace');
11786	    var newText = $.smartReplace.bulkReplace(oldText, $.smartReplace[replacements]);
11787	    $(obj).text(newText);
11788	  });
11789
11790	});
11791
11792
11793/***/ }),
11794
11795/***/ 334:
11796/***/ (function(module, exports) {
11797
11798	(function($) {
11799	  $.fn.bootstrapValidator.i18n.notEmpty = $.extend(
11800	    $.fn.bootstrapValidator.i18n.notEmpty || {},
11801	    {'default': 'Please enter a value'}
11802	  );
11803
11804	  $.fn.bootstrapValidator.validators.notEmpty = {
11805	    enableByHtml5: function($field) {
11806	      var required = $field.attr('required') + '';
11807	      return (required === 'required' || required === 'true');
11808	    },
11809
11810	    /**
11811	     * Check if input value is empty or not
11812	     *
11813	     * @param {BootstrapValidator} validator The validator plugin instance
11814	     * @param {jQuery} $field Field element
11815	     * @param {Object} options
11816	     * @returns {Boolean}
11817	     */
11818	    validate: function(validator, $field, options) {
11819	      var type = $field.attr('type');
11820
11821	      if (type === 'radio' || type === 'checkbox') {
11822	        return validator
11823	          .getFieldElements($field.attr('data-bv-field'))
11824	          .filter(':checked')
11825	          .length > 0;
11826	      }
11827
11828	      if (
11829	        type === 'number' &&
11830	        $field.get(0).validity &&
11831	        $field.get(0).validity.badInput === true
11832	      ) {
11833	        return true;
11834	      }
11835
11836	      return ($.trim($field.val()) !== '');
11837	    }
11838	  };
11839	}(window.jQuery));
11840
11841
11842/***/ }),
11843
11844/***/ 335:
11845/***/ (function(module, exports) {
11846
11847	/**
11848	 * Enchained Selects
11849	 *
11850	 * Enable a select once the user selects an option in a parent select.
11851	 *
11852	 * usage:
11853	 * <select data-enchained-select="#next-select-id">...</select>
11854	 **/
11855
11856	$(function(){
11857
11858	  $(document).on('change','*[data-enchained-select]', function(e){
11859	    $(e.target)
11860	      .closest('form').find('.control-fx').removeClass("current-selection");
11861	    // add the new value to smartReplace vars object:
11862	    $.smartReplace.vars[
11863	      $(e.target).data('smart-replace-field-name') || $(e.target).attr('id')
11864	    ] = $(e.target).val();
11865
11866	    //enable the next select and trigger the changed event:
11867	    var nextSelect = $(e.target).data('enchained-select');
11868	    //   $(nextSelect).prop('disabled', false);
11869	    $(nextSelect).trigger('parent-input:changed', {parent: e.target});
11870	    $(nextSelect).closest('.control-fx').addClass("current-selection");
11871	  });
11872
11873	  $(document).on('change','form select', function(e) {
11874	    $(e.target).closest('.control-fx').removeClass("current-selection");
11875	  });
11876
11877	});
11878
11879
11880/***/ }),
11881
11882/***/ 336:
11883/***/ (function(module, exports) {
11884
11885	$(function(){
11886
11887	  $(document).on('success.field.bv','[data-next-field-group]',function(e, data){
11888
11889	    // if there is a next field group set enable it by removing its disabled class:
11890	    if ( $(e.target).data('next-field-group') !== '') {
11891	      $('.form-group' + $(e.target).data('next-field-group') + ' .control-fx').removeClass('disabled');
11892	    }
11893
11894	    // enable of disable the field according to the field validation result:
11895	    if ( data.bv.isValid() ){
11896	      data.bv.$form.find('.form-submit .control-fx').removeClass('disabled');
11897	    }else{
11898	      data.bv.$form.find('.form-submit .control-fx').addClass('disabled');
11899	    }
11900
11901	  });
11902
11903	  $(document).on('error.field.bv','[data-next-field-group]',function(e, data){
11904
11905	    // if there is an error don't release the next field, add it the class disabled:
11906	    if ( $(e.target).data('next-field-group') !== '') {
11907	      $('.form-group' + $(e.target).data('next-field-group') + ' .control-fx').addClass('disabled');
11908	    }
11909	    // enable or disable the field according to the field validation result:
11910	    if ( data.bv.isValid() ){
11911	      data.bv.$form.find('.form-submit .control-fx').removeClass('disabled');
11912	    }else{
11913	      data.bv.$form.find('.form-submit .control-fx').addClass('disabled');
11914	    }
11915
11916	  });
11917
11918	});
11919
11920
11921/***/ }),
11922
11923/***/ 337:
11924/***/ (function(module, exports) {
11925
11926	/**
11927	 * Select Auto JSON
11928	 *
11929	 * Fills automatically a select from an external JSON file.
11930	 *
11931	 * usage:
11932	 * <select data-select-auto-json="{options}">...</select>
11933	 *
11934	 * {
11935	 *  "placeholder":"Select a Make...",
11936	 *  "source":"http://api.edmunds.com/api/vehicle/v2/makes?fmt=json&api_key=xtgymqcwqsuyk3ehjkdy44uf&status=used",
11937	 *  "parseObject":"makes",
11938	 *  "labelField":"name",
11939	 *  "valueField":"niceName"
11940	 * }
11941	 *
11942	 * placeholder and source are selfexplanatory.
11943	 * parseObject is the object in the response that you want to parse. (usually data)
11944	 * labelField is the field in the object you want to be used as field in the option appended to the select.
11945	 * valueField is the field in the object you want to be used as value in the option appended to the select.
11946	 **/
11947
11948	$(function(){
11949
11950	  var jsonResponseCache = {};
11951	  var jsonRequestCallbacks = {};
11952
11953	  $(document).on('enable parent-input:changed', '*[data-select-auto-json]', function(e, data){
11954	    var defaults = {
11955	      valueField: 'value',
11956	      labelField: 'field',
11957	      childValueField: 'value',
11958	      childLabelField: 'field',
11959	      parseObject: 'data',
11960	      sort: false, // string || number || false,  in conjunction with sortBy
11961	      ignoreEmptyValues: true,
11962	    };
11963
11964	    var options = $.extend({}, defaults, $(e.target).data('select-auto-json'));
11965	    $(e.target).trigger('disable');
11966
11967	    // only display the loading status of the select when the parent element has a valid value to make the json call:
11968	    if (e.type == 'parent-input:changed'){
11969	      if ( $(e.target).closest('form[data-bv]').data('bootstrapValidator').isValidField($(data.parent)) ){
11970	        $(e.target).closest('.control-fx').addClass('loading');
11971	      }
11972	    }
11973
11974
11975	    function getJSONCached(url, jsonCallback) {
11976	      // if there is a cached response for the requested url
11977	      if (jsonResponseCache[url] !== undefined) {
11978	        // call the callback directly with the response
11979	        jsonCallback.call(this, jsonResponseCache[url]);
11980	      // if there is no cached response for the requested url
11981	      } else {
11982	        // if there are no callbacks waiting to be handled for this url (ie. if
11983	        // the request is new)
11984	        if (jsonRequestCallbacks[url] === undefined) {
11985	          // create an array of callbacks
11986	          jsonRequestCallbacks[url] = [];
11987	          // perform the request
11988	          $.getJSON(url, function(json) {
11989	            // get the array of callbacks for this url
11990	            var jsonCallbacks = jsonRequestCallbacks[url];
11991	            var i;
11992	            // cache the response for future use
11993	            jsonResponseCache[url] = json;
11994	            // call each of the callbacks in the stack for the URL
11995	            for (i = 0; i < jsonCallbacks.length; i++) {
11996	              jsonCallbacks[i].call(this, json);
11997	            }
11998	            // delete request callbacks
11999	            jsonRequestCallbacks[url] = undefined;
12000	          });
12001	        }
12002	        // push the callback onto the stack waiting to be executed when the aja
12002x
12003	        // call has been completed
12004	        jsonRequestCallbacks[url].push(jsonCallback);
12005	      }
12006	    }
12007
12008	    getJSONCached($.smartReplace.replace(options.source, {}), function(json){
12009	      $(e.target).empty();
12010	      $(e.target).append( $('<option></option>').text(options.placeholder).val(''));
12011	      var sortBy = options.sortBy || options.labelField;
12012	      if (options.sort == 'number'){
12013	        json[options.parseObject].sort(function(a, b){
12014	          return b[sortBy] - a[options.labelField];
12015	        });
12016	      }else if(options.sort == 'string'){
12017	        json[options.parseObject].sort(function(a, b){
12018	          return a[sortBy].localeCompare(b[options.labelField]);
12019	        });
12020	      }
12021
12022	      $.each(json[options.parseObject], function(key, dataObj){
12023	        var value = dataObj[options.valueField];
12024	        var label = dataObj[options.labelField];
12025	        if ( options.labelReplace !== undefined ){
12026	          var reps = $.smartReplace[options.labelReplace];
12027	          label = $.smartReplace.bulkReplace(label, reps);
12028	        }
12029	        if (typeof(value) == 'object' ){
12030	          var $optGroup = $('<optgroup>',{label: label});
12031	          for (var i in value){
12032	            var childValue = value[i][options.childValueField];
12033	            var childLabel = value[i][options.childLabelField];
12034	            $optGroup.append($('<option></option>').text(childLabel).val(childValue));
12035	          }
12036	          $(e.target).append($optGroup);
12037
12038	        }else if(options.ignoreEmptyValues && value === ''){
12039	        }else{
12040	          $(e.target).append($('<option></option>').text(label).val(value));
12041	        }
12042	      });
12043	      $(e.target).trigger('select:set-initial-value');
12044	      $(e.target).prop('disabled', false);
12045	      $(e.target).closest('.control-fx').removeClass("disabled loading");
12046
12047	    });
12048	  });
12049
12050	  $(document).on('select:set-initial-value', 'select', function(e){
12051
12052	    // try to determine the initial value based on the current options:
12053	    if ($(e.target).data('single-option-autoselected')){
12054	      var $emptyOptions = $(e.target).find('[value=""]');
12055	      var $notEmptyOptions = $(e.target).find('option').not($emptyOptions);
12056	      if ( $notEmptyOptions.length === 1 ){
12057	        $(e.target).val($notEmptyOptions.get(0).value)
12058	          .trigger('change');
12059	        $emptyOptions.remove();
12060	      }
12061	    }
12062
12063	    // if we don't have a value yet try to load the value from the initial value provided from backend:
12064	    var initialValue = $(e.target).data('initial-value') || '';
12065
12066	    if (
12067	      $(e.target).val() === '' &&
12068	      initialValue !== '' &&
12069	      $(e.target).find('option[value="' + initialValue + '"]').length === 1
12070	    ){
12071	      // If there is an option with the initial value, selected and trigger
12072	      // change:
12073	      $(e.target).val(initialValue)
12074	        .trigger('change');
12075	      $(e.target).find('option[value=""]').attr('disabled', 'disabled');
12076	    }
12077	  });
12078
12079	  $(document).on('disable', '*[data-select-auto-json]', function(e){
12080	    var options = $(e.target).data('select-auto-json');
12081
12082	    $(e.target).empty();
12083	    $(e.target).append( $('<option></option>').text(options.placeholder).val(''));
12084	    $(e.target).prop('disabled', true);
12085	    $(e.target).closest('.control-fx').addClass("disabled");
12086
12087	    $(e.target).closest('form[data-bv]').bootstrapValidator('updateStatus', $(e.target), 'NOT_VALIDATED');
12088	    var nextSelect = $(e.target).data('enchained-select');
12089
12090	    if (nextSelect) {
12091	      $(nextSelect).trigger('disable');
12092	    }
12093	  });
12094
12095	});
12096
12097
12098/***/ }),
12099
12100/***/ 338:
12101/***/ (function(module, exports) {
12102
12103	$(function(){
12104
12105	  // display only one error at a time...
12106	  var $document = $(document);
12107	  $document.on(
12108	    'error.validator.bv',
12109	    'form.step1-form *',
12110	    function (e, data) {
12111	      data
12112	        .element
12113	        .closest('form')
12114	        .find('.has-error small.help-block')
12115	        .hide()
12116	        .eq(0)
12117	        .show();
12118	    }
12119	  );
12120
12121	  // enable/disable old flow based on year selection...
12122	  $document.on(
12123	    'change',
12124	    '.step1-form .car-year',
12125	    function(e) {
12126	      $(e.currentTarget).closest('form')
12127	        .find('.car-is-old').val(
12128	          ($(e.currentTarget).val() < 0) ? 1 : 0
12129	        );
12130	    }
12131	  );
12132
12133	});
12134
12135
12136/***/ }),
12137
12138/***/ 339:
12139/***/ (function(module, exports) {
12140
12141	/**
12142	* Set initial value of select elements from data structured in cookie
12143	*
12144	*
12145
12146	  Sample usage:
12147
12148	  1. Create a cookie structured whereby the value of the cookie contains field/
12149	     value pairs separated by pipe characters as follows:
12150	     wkdaCF_step1 = "manufacturer=060|maintype=A4|builtDate=2013"
12151
12152	  2. Add the data attribute to the select element identifying the cookie and the
12153	     variable name within the cookie as follows:
12154	      <select
12155	        name="selectname"
12156	        data-initial-value-cookie="wkdaCF_step1.maintype"
12157	      >
12158	*/
12159	$(function(){
12160
12161	  var $cookieDataElementCollection  = $('[data-initial-value-cookie]');
12162
12163	  // populate conversion form with any previous search data
12164	  function parseStr(
12165	    delimitedStr,
12166	    tupleDelimiterOperator,
12167	    variableAssignmentOperator
12168	  ) {
12169	    var parsedObject = {};
12170	    var tupleStringsArr;
12171	    var i;
12172	    var tupleArr;
12173	    var tupleName;
12174	    var tupleVal;
12175
12176	    // default for parsing cookies
12177	    tupleDelimiterOperator = tupleDelimiterOperator || ';';
12178	    variableAssignmentOperator = variableAssignmentOperator || '=';
12179	    tupleStringsArr = delimitedStr.split(tupleDelimiterOperator);
12180
12181	    for (i = 0; i < tupleStringsArr.length; i++) {
12182	      tupleArr = tupleStringsArr[i].split(variableAssignmentOperator);
12183	      if (tupleArr.length === 2) {
12184	        // strip leading and trailing white space from variable names
12185	        tupleName = tupleArr[0].replace(/(^\s+|\s$)/g, '');
12186	        tupleVal = tupleArr[1].replace(/(^\s+|\s$)/g, '');
12187	        parsedObject[tupleName] = tupleVal;
12188	      }
12189	    }
12190
12191	    return parsedObject;
12192	  }
12193
12194	  (function setInitialValues() {
12195	    var cookies = parseStr(document.cookie || '');
12196
12197	    $cookieDataElementCollection.each(function() {
12198	      var $cookieDataElement = $(this);
12199	      var cookieInitialValueVarName =
12200	        $cookieDataElement.data('initial-value-cookie');
12201	      var cookieInitialValueVarNameArr = cookieInitialValueVarName.split('.');
12202	      var cookieName = cookieInitialValueVarNameArr[0];
12203	      var cookieVarName = cookieInitialValueVarNameArr[1];
12204	      var formCookieStr = cookies[cookieName];
12205	      var formCookie;
12206
12207	      if ($cookieDataElement.val()) {
12208	        $cookieDataElement.trigger('change');
12209	      }
12210
12211	      if ($cookieDataElement.is(":focus")) {
12212	        return false;
12213	      }
12214
12215	      if (formCookieStr !== undefined) {
12216	        formCookie =
12217	          parseStr(decodeURIComponent(formCookieStr.replace(/\+/g, '%20')), '|');
12218	        $cookieDataElement
12219	          .data(
12220	            'initial-value',
12221	            formCookie[cookieVarName]
12222	          )
12223	          .trigger('select:set-initial-value');
12224	      }
12225	    });
12226	  })();
12227
12228	});
12229
12230
12231/***/ })
12232
12233/******/ });

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.