/*! Magnific Popup - v0.9.9 - 2013-12-27
 * http://dimsemenov.com/plugins/magnific-popup/
 * Copyright (c) 2013 Dmitry Semenov; */
;(function($) {

	/*>>core*/
	/**
	 *
	 * Magnific Popup Core JS file
	 *
	 */


	/**
	 * Private static constants
	 */
	var CLOSE_EVENT = 'Close',
		BEFORE_CLOSE_EVENT = 'BeforeClose',
		AFTER_CLOSE_EVENT = 'AfterClose',
		BEFORE_APPEND_EVENT = 'BeforeAppend',
		MARKUP_PARSE_EVENT = 'MarkupParse',
		OPEN_EVENT = 'Open',
		CHANGE_EVENT = 'Change',
		NS = 'mfp',
		EVENT_NS = '.' + NS,
		READY_CLASS = 'mfp-ready',
		REMOVING_CLASS = 'mfp-removing',
		PREVENT_CLOSE_CLASS = 'mfp-prevent-close';


	/**
	 * Private vars
	 */
	var mfp, // As we have only one instance of MagnificPopup object, we define it locally to not to use 'this'
		MagnificPopup = function(){},
		_isJQ = !!(window.jQuery),
		_prevStatus,
		_window = $(window),
		_body,
		_document,
		_prevContentType,
		_wrapClasses,
		_currPopupType;


	/**
	 * Private functions
	 */
	var _mfpOn = function(name, f) {
			mfp.ev.on(NS + name + EVENT_NS, f);
		},
		_getEl = function(className, appendTo, html, raw) {
			var el = document.createElement('div');
			el.className = 'mfp-'+className;
			if(html) {
				el.innerHTML = html;
			}
			if(!raw) {
				el = $(el);
				if(appendTo) {
					el.appendTo(appendTo);
				}
			} else if(appendTo) {
				appendTo.appendChild(el);
			}
			return el;
		},
		_mfpTrigger = function(e, data) {
			mfp.ev.triggerHandler(NS + e, data);

			if(mfp.st.callbacks) {
				// converts "mfpEventName" to "eventName" callback and triggers it if it's present
				e = e.charAt(0).toLowerCase() + e.slice(1);
				if(mfp.st.callbacks[e]) {
					mfp.st.callbacks[e].apply(mfp, $.isArray(data) ? data : [data]);
				}
			}
		},
		_getCloseBtn = function(type) {
			if(type !== _currPopupType || !mfp.currTemplate.closeBtn) {
				mfp.currTemplate.closeBtn = $( mfp.st.closeMarkup.replace('%title%', mfp.st.tClose ) );
				_currPopupType = type;
			}
			return mfp.currTemplate.closeBtn;
		},
	// Initialize Magnific Popup only when called at least once
		_checkInstance = function() {
			if(!$.magnificPopup.instance) {
				mfp = new MagnificPopup();
				mfp.init();
				$.magnificPopup.instance = mfp;
			}
		},
	// CSS transition detection, http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr
		supportsTransitions = function() {
			var s = document.createElement('p').style, // 's' for style. better to create an element if body yet to exist
				v = ['ms','O','Moz','Webkit']; // 'v' for vendor

			if( s['transition'] !== undefined ) {
				return true;
			}

			while( v.length ) {
				if( v.pop() + 'Transition' in s ) {
					return true;
				}
			}

			return false;
		};



	/**
	 * Public functions
	 */
	MagnificPopup.prototype = {

		constructor: MagnificPopup,

		/**
		 * Initializes Magnific Popup plugin.
		 * This function is triggered only once when $.fn.magnificPopup or $.magnificPopup is executed
		 */
		init: function() {
			var appVersion = navigator.appVersion;
			mfp.isIE7 = appVersion.indexOf("MSIE 7.") !== -1;
			mfp.isIE8 = appVersion.indexOf("MSIE 8.") !== -1;
			mfp.isLowIE = mfp.isIE7 || mfp.isIE8;
			mfp.isAndroid = (/android/gi).test(appVersion);
			mfp.isIOS = (/iphone|ipad|ipod/gi).test(appVersion);
			mfp.supportsTransition = supportsTransitions();

			// We disable fixed positioned lightbox on devices that don't handle it nicely.
			// If you know a better way of detecting this - let me know.
			mfp.probablyMobile = (mfp.isAndroid || mfp.isIOS || /(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent) );
			_document = $(document);

			mfp.popupsCache = {};
		},

		/**
		 * Opens popup
		 * @param  data [description]
		 */
		open: function(data) {

			if(!_body) {
				_body = $(document.body);
			}

			var i;

			if(data.isObj === false) {
				// convert jQuery collection to array to avoid conflicts later
				mfp.items = data.items.toArray();

				mfp.index = 0;
				var items = data.items,
					item;
				for(i = 0; i < items.length; i++) {
					item = items[i];
					if(item.parsed) {
						item = item.el[0];
					}
					if(item === data.el[0]) {
						mfp.index = i;
						break;
					}
				}
			} else {
				mfp.items = $.isArray(data.items) ? data.items : [data.items];
				mfp.index = data.index || 0;
			}

			// if popup is already opened - we just update the content
			if(mfp.isOpen) {
				mfp.updateItemHTML();
				return;
			}

			mfp.types = [];
			_wrapClasses = '';
			if(data.mainEl && data.mainEl.length) {
				mfp.ev = data.mainEl.eq(0);
			} else {
				mfp.ev = _document;
			}

			if(data.key) {
				if(!mfp.popupsCache[data.key]) {
					mfp.popupsCache[data.key] = {};
				}
				mfp.currTemplate = mfp.popupsCache[data.key];
			} else {
				mfp.currTemplate = {};
			}



			mfp.st = $.extend(true, {}, $.magnificPopup.defaults, data );
			mfp.fixedContentPos = mfp.st.fixedContentPos === 'auto' ? !mfp.probablyMobile : mfp.st.fixedContentPos;

			if(mfp.st.modal) {
				mfp.st.closeOnContentClick = false;
				mfp.st.closeOnBgClick = false;
				mfp.st.showCloseBtn = false;
				mfp.st.enableEscapeKey = false;
			}


			// Building markup
			// main containers are created only once
			if(!mfp.bgOverlay) {

				// Dark overlay
				mfp.bgOverlay = _getEl('bg').on('click'+EVENT_NS, function() {
					mfp.close();
				});

				mfp.wrap = _getEl('wrap').attr('tabindex', -1).on('click'+EVENT_NS, function(e) {
					if(mfp._checkIfClose(e.target)) {
						mfp.close();
					}
				});

				mfp.container = _getEl('container', mfp.wrap);
			}

			mfp.contentContainer = _getEl('content');
			if(mfp.st.preloader) {
				mfp.preloader = _getEl('preloader', mfp.container, mfp.st.tLoading);
			}


			// Initializing modules
			var modules = $.magnificPopup.modules;
			for(i = 0; i < modules.length; i++) {
				var n = modules[i];
				n = n.charAt(0).toUpperCase() + n.slice(1);
				mfp['init'+n].call(mfp);
			}
			_mfpTrigger('BeforeOpen');


			if(mfp.st.showCloseBtn) {
				// Close button
				if(!mfp.st.closeBtnInside) {
					mfp.wrap.append( _getCloseBtn() );
				} else {
					_mfpOn(MARKUP_PARSE_EVENT, function(e, template, values, item) {
						values.close_replaceWith = _getCloseBtn(item.type);
					});
					_wrapClasses += ' mfp-close-btn-in';
				}
			}

			if(mfp.st.alignTop) {
				_wrapClasses += ' mfp-align-top';
			}



			if(mfp.fixedContentPos) {
				mfp.wrap.css({
					overflow: mfp.st.overflowY,
					overflowX: 'hidden',
					overflowY: mfp.st.overflowY
				});
			} else {
				mfp.wrap.css({
					top: _window.scrollTop(),
					position: 'absolute'
				});
			}
			if( mfp.st.fixedBgPos === false || (mfp.st.fixedBgPos === 'auto' && !mfp.fixedContentPos) ) {
				mfp.bgOverlay.css({
					height: _document.height(),
					position: 'absolute'
				});
			}



			if(mfp.st.enableEscapeKey) {
				// Close on ESC key
				_document.on('keyup' + EVENT_NS, function(e) {
					if(e.keyCode === 27) {
						mfp.close();
					}
				});
			}

			_window.on('resize' + EVENT_NS, function() {
				mfp.updateSize();
			});


			if(!mfp.st.closeOnContentClick) {
				_wrapClasses += ' mfp-auto-cursor';
			}

			if(_wrapClasses)
				mfp.wrap.addClass(_wrapClasses);


			// this triggers recalculation of layout, so we get it once to not to trigger twice
			var windowHeight = mfp.wH = _window.height();


			var windowStyles = {};

			if( mfp.fixedContentPos ) {
				if(mfp._hasScrollBar(windowHeight)){
					var s = mfp._getScrollbarSize();
					if(s) {
						windowStyles.marginRight = s;
					}
				}
			}

			if(mfp.fixedContentPos) {
				if(!mfp.isIE7) {
					windowStyles.overflow = 'hidden';
				} else {
					// ie7 double-scroll bug
					$('body, html').css('overflow', 'hidden');
				}
			}



			var classesToadd = mfp.st.mainClass;
			if(mfp.isIE7) {
				classesToadd += ' mfp-ie7';
			}
			if(classesToadd) {
				mfp._addClassToMFP( classesToadd );
			}

			// add content
			mfp.updateItemHTML();

			_mfpTrigger('BuildControls');

			// remove scrollbar, add margin e.t.c
			$('html').css(windowStyles);

			// add everything to DOM
			mfp.bgOverlay.add(mfp.wrap).prependTo( mfp.st.prependTo || _body );

			// Save last focused element
			mfp._lastFocusedEl = document.activeElement;

			// Wait for next cycle to allow CSS transition
			setTimeout(function() {

				if(mfp.content) {
					mfp._addClassToMFP(READY_CLASS);
					mfp._setFocus();
				} else {
					// if content is not defined (not loaded e.t.c) we add class only for BG
					mfp.bgOverlay.addClass(READY_CLASS);
				}

				// Trap the focus in popup
				_document.on('focusin' + EVENT_NS, mfp._onFocusIn);

			}, 16);

			mfp.isOpen = true;
			mfp.updateSize(windowHeight);
			_mfpTrigger(OPEN_EVENT);

			return data;
		},

		/**
		 * Closes the popup
		 */
		close: function() {
			if(!mfp.isOpen) return;
			_mfpTrigger(BEFORE_CLOSE_EVENT);

			mfp.isOpen = false;
			// for CSS3 animation
			if(mfp.st.removalDelay && !mfp.isLowIE && mfp.supportsTransition )  {
				mfp._addClassToMFP(REMOVING_CLASS);
				setTimeout(function() {
					mfp._close();
				}, mfp.st.removalDelay);
			} else {
				mfp._close();
			}
		},

		/**
		 * Helper for close() function
		 */
		_close: function() {
			_mfpTrigger(CLOSE_EVENT);

			var classesToRemove = REMOVING_CLASS + ' ' + READY_CLASS + ' ';

			mfp.bgOverlay.detach();
			mfp.wrap.detach();
			mfp.container.empty();

			if(mfp.st.mainClass) {
				classesToRemove += mfp.st.mainClass + ' ';
			}

			mfp._removeClassFromMFP(classesToRemove);

			if(mfp.fixedContentPos) {
				var windowStyles = {marginRight: ''};
				if(mfp.isIE7) {
					$('body, html').css('overflow', '');
				} else {
					windowStyles.overflow = '';
				}
				$('html').css(windowStyles);
			}

			_document.off('keyup' + EVENT_NS + ' focusin' + EVENT_NS);
			mfp.ev.off(EVENT_NS);

			// clean up DOM elements that aren't removed
			mfp.wrap.attr('class', 'mfp-wrap').removeAttr('style');
			mfp.bgOverlay.attr('class', 'mfp-bg');
			mfp.container.attr('class', 'mfp-container');

			// remove close button from target element
			if(mfp.st.showCloseBtn &&
				(!mfp.st.closeBtnInside || mfp.currTemplate[mfp.currItem.type] === true)) {
				if(mfp.currTemplate.closeBtn)
					mfp.currTemplate.closeBtn.detach();
			}


			if(mfp._lastFocusedEl) {
				$(mfp._lastFocusedEl).focus(); // put tab focus back
			}
			mfp.currItem = null;
			mfp.content = null;
			mfp.currTemplate = null;
			mfp.prevHeight = 0;

			_mfpTrigger(AFTER_CLOSE_EVENT);
		},

		updateSize: function(winHeight) {

			if(mfp.isIOS) {
				// fixes iOS nav bars https://github.com/dimsemenov/Magnific-Popup/issues/2
				var zoomLevel = document.documentElement.clientWidth / window.innerWidth;
				var height = window.innerHeight * zoomLevel;
				mfp.wrap.css('height', height);
				mfp.wH = height;
			} else {
				mfp.wH = winHeight || _window.height();
			}
			// Fixes #84: popup incorrectly positioned with position:relative on body
			if(!mfp.fixedContentPos) {
				mfp.wrap.css('height', mfp.wH);
			}

			_mfpTrigger('Resize');

		},

		/**
		 * Set content of popup based on current index
		 */
		updateItemHTML: function() {
			var item = mfp.items[mfp.index];

			// Detach and perform modifications
			mfp.contentContainer.detach();

			if(mfp.content)
				mfp.content.detach();

			if(!item.parsed) {
				item = mfp.parseEl( mfp.index );
			}

			var type = item.type;

			_mfpTrigger('BeforeChange', [mfp.currItem ? mfp.currItem.type : '', type]);
			// BeforeChange event works like so:
			// _mfpOn('BeforeChange', function(e, prevType, newType) { });

			mfp.currItem = item;





			if(!mfp.currTemplate[type]) {
				var markup = mfp.st[type] ? mfp.st[type].markup : false;

				// allows to modify markup
				_mfpTrigger('FirstMarkupParse', markup);

				if(markup) {
					mfp.currTemplate[type] = $(markup);
				} else {
					// if there is no markup found we just define that template is parsed
					mfp.currTemplate[type] = true;
				}
			}

			if(_prevContentType && _prevContentType !== item.type) {
				mfp.container.removeClass('mfp-'+_prevContentType+'-holder');
			}

			var newContent = mfp['get' + type.charAt(0).toUpperCase() + type.slice(1)](item, mfp.currTemplate[type]);
			mfp.appendContent(newContent, type);

			item.preloaded = true;

			_mfpTrigger(CHANGE_EVENT, item);
			_prevContentType = item.type;

			// Append container back after its content changed
			mfp.container.prepend(mfp.contentContainer);

			_mfpTrigger('AfterChange');
		},


		/**
		 * Set HTML content of popup
		 */
		appendContent: function(newContent, type) {
			mfp.content = newContent;

			if(newContent) {
				if(mfp.st.showCloseBtn && mfp.st.closeBtnInside &&
					mfp.currTemplate[type] === true) {
					// if there is no markup, we just append close button element inside
					if(!mfp.content.find('.mfp-close').length) {
						mfp.content.append(_getCloseBtn());
					}
				} else {
					mfp.content = newContent;
				}
			} else {
				mfp.content = '';
			}

			_mfpTrigger(BEFORE_APPEND_EVENT);
			mfp.container.addClass('mfp-'+type+'-holder');

			mfp.contentContainer.append(mfp.content);
		},




		/**
		 * Creates Magnific Popup data object based on given data
		 * @param  {int} index Index of item to parse
		 */
		parseEl: function(index) {
			var item = mfp.items[index],
				type;

			if(item.tagName) {
				item = { el: $(item) };
			} else {
				type = item.type;
				item = { data: item, src: item.src };
			}

			if(item.el) {
				var types = mfp.types;

				// check for 'mfp-TYPE' class
				for(var i = 0; i < types.length; i++) {
					if( item.el.hasClass('mfp-'+types[i]) ) {
						type = types[i];
						break;
					}
				}

				item.src = item.el.attr('data-mfp-src');
				if(!item.src) {
					item.src = item.el.attr('href');
				}
			}

			item.type = type || mfp.st.type || 'inline';
			item.index = index;
			item.parsed = true;
			mfp.items[index] = item;
			_mfpTrigger('ElementParse', item);

			return mfp.items[index];
		},


		/**
		 * Initializes single popup or a group of popups
		 */
		addGroup: function(el, options) {
			var eHandler = function(e) {
				e.mfpEl = this;
				mfp._openClick(e, el, options);
			};

			if(!options) {
				options = {};
			}

			var eName = 'click.magnificPopup';
			options.mainEl = el;

			if(options.items) {
				options.isObj = true;
				el.off(eName).on(eName, eHandler);
			} else {
				options.isObj = false;
				if(options.delegate) {
					el.off(eName).on(eName, options.delegate , eHandler);
				} else {
					options.items = el;
					el.off(eName).on(eName, eHandler);
				}
			}
		},
		_openClick: function(e, el, options) {
			var midClick = options.midClick !== undefined ? options.midClick : $.magnificPopup.defaults.midClick;


			if(!midClick && ( e.which === 2 || e.ctrlKey || e.metaKey ) ) {
				return;
			}

			var disableOn = options.disableOn !== undefined ? options.disableOn : $.magnificPopup.defaults.disableOn;

			if(disableOn) {
				if($.isFunction(disableOn)) {
					if( !disableOn.call(mfp) ) {
						return true;
					}
				} else { // else it's number
					if( _window.width() < disableOn ) {
						return true;
					}
				}
			}

			if(e.type) {
				e.preventDefault();

				// This will prevent popup from closing if element is inside and popup is already opened
				if(mfp.isOpen) {
					e.stopPropagation();
				}
			}


			options.el = $(e.mfpEl);
			if(options.delegate) {
				options.items = el.find(options.delegate);
			}
			mfp.open(options);
		},


		/**
		 * Updates text on preloader
		 */
		updateStatus: function(status, text) {

			if(mfp.preloader) {
				if(_prevStatus !== status) {
					mfp.container.removeClass('mfp-s-'+_prevStatus);
				}

				if(!text && status === 'loading') {
					text = mfp.st.tLoading;
				}

				var data = {
					status: status,
					text: text
				};
				// allows to modify status
				_mfpTrigger('UpdateStatus', data);

				status = data.status;
				text = data.text;

				mfp.preloader.html(text);

				mfp.preloader.find('a').on('click', function(e) {
					e.stopImmediatePropagation();
				});

				mfp.container.addClass('mfp-s-'+status);
				_prevStatus = status;
			}
		},


		/*
		 "Private" helpers that aren't private at all
		 */
		// Check to close popup or not
		// "target" is an element that was clicked
		_checkIfClose: function(target) {

			if($(target).hasClass(PREVENT_CLOSE_CLASS)) {
				return;
			}

			var closeOnContent = mfp.st.closeOnContentClick;
			var closeOnBg = mfp.st.closeOnBgClick;

			if(closeOnContent && closeOnBg) {
				return true;
			} else {

				// We close the popup if click is on close button or on preloader. Or if there is no content.
				if(!mfp.content || $(target).hasClass('mfp-close') || (mfp.preloader && target === mfp.preloader[0]) ) {
					return true;
				}

				// if click is outside the content
				if(  (target !== mfp.content[0] && !$.contains(mfp.content[0], target))  ) {
					if(closeOnBg) {
						// last check, if the clicked element is in DOM, (in case it's removed onclick)
						if( $.contains(document, target) ) {
							return true;
						}
					}
				} else if(closeOnContent) {
					return true;
				}

			}
			return false;
		},
		_addClassToMFP: function(cName) {
			mfp.bgOverlay.addClass(cName);
			mfp.wrap.addClass(cName);
		},
		_removeClassFromMFP: function(cName) {
			this.bgOverlay.removeClass(cName);
			mfp.wrap.removeClass(cName);
		},
		_hasScrollBar: function(winHeight) {
			return (  (mfp.isIE7 ? _document.height() : document.body.scrollHeight) > (winHeight || _window.height()) );
		},
		_setFocus: function() {
			(mfp.st.focus ? mfp.content.find(mfp.st.focus).eq(0) : mfp.wrap).focus();
		},
		_onFocusIn: function(e) {
			if( e.target !== mfp.wrap[0] && !$.contains(mfp.wrap[0], e.target) ) {
				mfp._setFocus();
				return false;
			}
		},
		_parseMarkup: function(template, values, item) {
			var arr;
			if(item.data) {
				values = $.extend(item.data, values);
			}
			_mfpTrigger(MARKUP_PARSE_EVENT, [template, values, item] );

			$.each(values, function(key, value) {
				if(value === undefined || value === false) {
					return true;
				}
				arr = key.split('_');
				if(arr.length > 1) {
					var el = template.find(EVENT_NS + '-'+arr[0]);

					if(el.length > 0) {
						var attr = arr[1];
						if(attr === 'replaceWith') {
							if(el[0] !== value[0]) {
								el.replaceWith(value);
							}
						} else if(attr === 'img') {
							if(el.is('img')) {
								el.attr('src', value);
							} else {
								el.replaceWith( '<img src="'+value+'" class="' + el.attr('class') + '" />' );
							}
						} else {
							el.attr(arr[1], value);
						}
					}

				} else {
					template.find(EVENT_NS + '-'+key).html(value);
				}
			});
		},

		_getScrollbarSize: function() {
			// thx David
			if(mfp.scrollbarSize === undefined) {
				var scrollDiv = document.createElement("div");
				scrollDiv.id = "mfp-sbm";
				scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;';
				document.body.appendChild(scrollDiv);
				mfp.scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;
				document.body.removeChild(scrollDiv);
			}
			return mfp.scrollbarSize;
		}

	}; /* MagnificPopup core prototype end */




	/**
	 * Public static functions
	 */
	$.magnificPopup = {
		instance: null,
		proto: MagnificPopup.prototype,
		modules: [],

		open: function(options, index) {
			_checkInstance();

			if(!options) {
				options = {};
			} else {
				options = $.extend(true, {}, options);
			}


			options.isObj = true;
			options.index = index || 0;
			return this.instance.open(options);
		},

		close: function() {
			return $.magnificPopup.instance && $.magnificPopup.instance.close();
		},

		registerModule: function(name, module) {
			if(module.options) {
				$.magnificPopup.defaults[name] = module.options;
			}
			$.extend(this.proto, module.proto);
			this.modules.push(name);
		},

		defaults: {

			// Info about options is in docs:
			// http://dimsemenov.com/plugins/magnific-popup/documentation.html#options

			disableOn: 0,

			key: null,

			midClick: false,

			mainClass: '',

			preloader: true,

			focus: '', // CSS selector of input to focus after popup is opened

			closeOnContentClick: false,

			closeOnBgClick: true,

			closeBtnInside: true,

			showCloseBtn: true,

			enableEscapeKey: true,

			modal: false,

			alignTop: false,

			removalDelay: 0,

			prependTo: null,

			fixedContentPos: 'auto',

			fixedBgPos: 'auto',

			overflowY: 'auto',

			closeMarkup: '<button title="%title%" type="button" class="mfp-close">&times;</button>',

			tClose: 'Close (Esc)',

			tLoading: 'Loading...'

		}
	};



	$.fn.magnificPopup = function(options) {
		_checkInstance();

		var jqEl = $(this);

		// We call some API method of first param is a string
		if (typeof options === "string" ) {

			if(options === 'open') {
				var items,
					itemOpts = _isJQ ? jqEl.data('magnificPopup') : jqEl[0].magnificPopup,
					index = parseInt(arguments[1], 10) || 0;

				if(itemOpts.items) {
					items = itemOpts.items[index];
				} else {
					items = jqEl;
					if(itemOpts.delegate) {
						items = items.find(itemOpts.delegate);
					}
					items = items.eq( index );
				}
				mfp._openClick({mfpEl:items}, jqEl, itemOpts);
			} else {
				if(mfp.isOpen)
					mfp[options].apply(mfp, Array.prototype.slice.call(arguments, 1));
			}

		} else {
			// clone options obj
			options = $.extend(true, {}, options);

			/*
			 * As Zepto doesn't support .data() method for objects
			 * and it works only in normal browsers
			 * we assign "options" object directly to the DOM element. FTW!
			 */
			if(_isJQ) {
				jqEl.data('magnificPopup', options);
			} else {
				jqEl[0].magnificPopup = options;
			}

			mfp.addGroup(jqEl, options);

		}
		return jqEl;
	};


//Quick benchmark
	/*
	 var start = performance.now(),
	 i,
	 rounds = 1000;

	 for(i = 0; i < rounds; i++) {

	 }
	 console.log('Test #1:', performance.now() - start);

	 start = performance.now();
	 for(i = 0; i < rounds; i++) {

	 }
	 console.log('Test #2:', performance.now() - start);
	 */


	/*>>core*/

	/*>>inline*/

	var INLINE_NS = 'inline',
		_hiddenClass,
		_inlinePlaceholder,
		_lastInlineElement,
		_putInlineElementsBack = function() {
			if(_lastInlineElement) {
				_inlinePlaceholder.after( _lastInlineElement.addClass(_hiddenClass) ).detach();
				_lastInlineElement = null;
			}
		};

	$.magnificPopup.registerModule(INLINE_NS, {
		options: {
			hiddenClass: 'hide', // will be appended with `mfp-` prefix
			markup: '',
			tNotFound: 'Content not found'
		},
		proto: {

			initInline: function() {
				mfp.types.push(INLINE_NS);

				_mfpOn(CLOSE_EVENT+'.'+INLINE_NS, function() {
					_putInlineElementsBack();
				});
			},

			getInline: function(item, template) {

				_putInlineElementsBack();

				if(item.src) {
					var inlineSt = mfp.st.inline,
						el = $(item.src);

					if(el.length) {

						// If target element has parent - we replace it with placeholder and put it back after popup is closed
						var parent = el[0].parentNode;
						if(parent && parent.tagName) {
							if(!_inlinePlaceholder) {
								_hiddenClass = inlineSt.hiddenClass;
								_inlinePlaceholder = _getEl(_hiddenClass);
								_hiddenClass = 'mfp-'+_hiddenClass;
							}
							// replace target inline element with placeholder
							_lastInlineElement = el.after(_inlinePlaceholder).detach().removeClass(_hiddenClass);
						}

						mfp.updateStatus('ready');
					} else {
						mfp.updateStatus('error', inlineSt.tNotFound);
						el = $('<div>');
					}

					item.inlineElement = el;
					return el;
				}

				mfp.updateStatus('ready');
				mfp._parseMarkup(template, {}, item);
				return template;
			}
		}
	});

	/*>>inline*/

	/*>>ajax*/
	var AJAX_NS = 'ajax',
		_ajaxCur,
		_removeAjaxCursor = function() {
			if(_ajaxCur) {
				_body.removeClass(_ajaxCur);
			}
		},
		_destroyAjaxRequest = function() {
			_removeAjaxCursor();
			if(mfp.req) {
				mfp.req.abort();
			}
		};

	$.magnificPopup.registerModule(AJAX_NS, {

		options: {
			settings: null,
			cursor: 'mfp-ajax-cur',
			tError: '<a href="%url%">The content</a> could not be loaded.'
		},

		proto: {
			initAjax: function() {
				mfp.types.push(AJAX_NS);
				_ajaxCur = mfp.st.ajax.cursor;

				_mfpOn(CLOSE_EVENT+'.'+AJAX_NS, _destroyAjaxRequest);
				_mfpOn('BeforeChange.' + AJAX_NS, _destroyAjaxRequest);
			},
			getAjax: function(item) {

				if(_ajaxCur)
					_body.addClass(_ajaxCur);

				mfp.updateStatus('loading');

				var opts = $.extend({
					url: item.src,
					success: function(data, textStatus, jqXHR) {
						var temp = {
							data:data,
							xhr:jqXHR
						};

						_mfpTrigger('ParseAjax', temp);

						mfp.appendContent( $(temp.data), AJAX_NS );

						item.finished = true;

						_removeAjaxCursor();

						mfp._setFocus();

						setTimeout(function() {
							mfp.wrap.addClass(READY_CLASS);
						}, 16);

						mfp.updateStatus('ready');

						_mfpTrigger('AjaxContentAdded');
					},
					error: function() {
						_removeAjaxCursor();
						item.finished = item.loadError = true;
						mfp.updateStatus('error', mfp.st.ajax.tError.replace('%url%', item.src));
					}
				}, mfp.st.ajax.settings);

				mfp.req = $.ajax(opts);

				return '';
			}
		}
	});







	/*>>ajax*/

	/*>>image*/
	var _imgInterval,
		_getTitle = function(item) {
			if(item.data && item.data.title !== undefined)
				return item.data.title;

			var src = mfp.st.image.titleSrc;

			if(src) {
				if($.isFunction(src)) {
					return src.call(mfp, item);
				} else if(item.el) {
					return item.el.attr(src) || '';
				}
			}
			return '';
		};

	$.magnificPopup.registerModule('image', {

		options: {
			markup: '<div class="mfp-figure">'+
				'<div class="mfp-close"></div>'+
				'<figure>'+
				'<div class="mfp-img"></div>'+
				'<figcaption>'+
				'<div class="mfp-bottom-bar">'+
				'<div class="mfp-title"></div>'+
				'<div class="mfp-counter"></div>'+
				'</div>'+
				'</figcaption>'+
				'</figure>'+
				'</div>',
			cursor: 'mfp-zoom-out-cur',
			titleSrc: 'title',
			verticalFit: true,
			tError: '<a href="%url%">The image</a> could not be loaded.'
		},

		proto: {
			initImage: function() {
				var imgSt = mfp.st.image,
					ns = '.image';

				mfp.types.push('image');

				_mfpOn(OPEN_EVENT+ns, function() {
					if(mfp.currItem.type === 'image' && imgSt.cursor) {
						_body.addClass(imgSt.cursor);
					}
				});

				_mfpOn(CLOSE_EVENT+ns, function() {
					if(imgSt.cursor) {
						_body.removeClass(imgSt.cursor);
					}
					_window.off('resize' + EVENT_NS);
				});

				_mfpOn('Resize'+ns, mfp.resizeImage);
				if(mfp.isLowIE) {
					_mfpOn('AfterChange', mfp.resizeImage);
				}
			},
			resizeImage: function() {
				var item = mfp.currItem;
				if(!item || !item.img) return;

				if(mfp.st.image.verticalFit) {
					var decr = 0;
					// fix box-sizing in ie7/8
					if(mfp.isLowIE) {
						decr = parseInt(item.img.css('padding-top'), 10) + parseInt(item.img.css('padding-bottom'),10);
					}
					item.img.css('max-height', mfp.wH-decr);
				}
			},
			_onImageHasSize: function(item) {
				if(item.img) {

					item.hasSize = true;

					if(_imgInterval) {
						clearInterval(_imgInterval);
					}

					item.isCheckingImgSize = false;

					_mfpTrigger('ImageHasSize', item);

					if(item.imgHidden) {
						if(mfp.content)
							mfp.content.removeClass('mfp-loading');

						item.imgHidden = false;
					}

				}
			},

			/**
			 * Function that loops until the image has size to display elements that rely on it asap
			 */
			findImageSize: function(item) {

				var counter = 0,
					img = item.img[0],
					mfpSetInterval = function(delay) {

						if(_imgInterval) {
							clearInterval(_imgInterval);
						}
						// decelerating interval that checks for size of an image
						_imgInterval = setInterval(function() {
							if(img.naturalWidth > 0) {
								mfp._onImageHasSize(item);
								return;
							}

							if(counter > 200) {
								clearInterval(_imgInterval);
							}

							counter++;
							if(counter === 3) {
								mfpSetInterval(10);
							} else if(counter === 40) {
								mfpSetInterval(50);
							} else if(counter === 100) {
								mfpSetInterval(500);
							}
						}, delay);
					};

				mfpSetInterval(1);
			},

			getImage: function(item, template) {

				var guard = 0,

				// image load complete handler
					onLoadComplete = function() {
						if(item) {
							if (item.img[0].complete) {
								item.img.off('.mfploader');

								if(item === mfp.currItem){
									mfp._onImageHasSize(item);

									mfp.updateStatus('ready');
								}

								item.hasSize = true;
								item.loaded = true;

								_mfpTrigger('ImageLoadComplete');

							}
							else {
								// if image complete check fails 200 times (20 sec), we assume that there was an error.
								guard++;
								if(guard < 200) {
									setTimeout(onLoadComplete,100);
								} else {
									onLoadError();
								}
							}
						}
					},

				// image error handler
					onLoadError = function() {
						if(item) {
							item.img.off('.mfploader');
							if(item === mfp.currItem){
								mfp._onImageHasSize(item);
								mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
							}

							item.hasSize = true;
							item.loaded = true;
							item.loadError = true;
						}
					},
					imgSt = mfp.st.image;


				var el = template.find('.mfp-img');
				if(el.length) {
					var img = document.createElement('img');
					img.className = 'mfp-img';
					item.img = $(img).on('load.mfploader', onLoadComplete).on('error.mfploader', onLoadError);
					img.src = item.src;

					// without clone() "error" event is not firing when IMG is replaced by new IMG
					// TODO: find a way to avoid such cloning
					if(el.is('img')) {
						item.img = item.img.clone();
					}

					img = item.img[0];
					if(img.naturalWidth > 0) {
						item.hasSize = true;
					} else if(!img.width) {
						item.hasSize = false;
					}
				}

				mfp._parseMarkup(template, {
					title: _getTitle(item),
					img_replaceWith: item.img
				}, item);

				mfp.resizeImage();

				if(item.hasSize) {
					if(_imgInterval) clearInterval(_imgInterval);

					if(item.loadError) {
						template.addClass('mfp-loading');
						mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
					} else {
						template.removeClass('mfp-loading');
						mfp.updateStatus('ready');
					}
					return template;
				}

				mfp.updateStatus('loading');
				item.loading = true;

				if(!item.hasSize) {
					item.imgHidden = true;
					template.addClass('mfp-loading');
					mfp.findImageSize(item);
				}

				return template;
			}
		}
	});



	/*>>image*/

	/*>>zoom*/
	var hasMozTransform,
		getHasMozTransform = function() {
			if(hasMozTransform === undefined) {
				hasMozTransform = document.createElement('p').style.MozTransform !== undefined;
			}
			return hasMozTransform;
		};

	$.magnificPopup.registerModule('zoom', {

		options: {
			enabled: false,
			easing: 'ease-in-out',
			duration: 300,
			opener: function(element) {
				return element.is('img') ? element : element.find('img');
			}
		},

		proto: {

			initZoom: function() {
				var zoomSt = mfp.st.zoom,
					ns = '.zoom',
					image;

				if(!zoomSt.enabled || !mfp.supportsTransition) {
					return;
				}

				var duration = zoomSt.duration,
					getElToAnimate = function(image) {
						var newImg = image.clone().removeAttr('style').removeAttr('class').addClass('mfp-animated-image'),
							transition = 'all '+(zoomSt.duration/1000)+'s ' + zoomSt.easing,
							cssObj = {
								position: 'fixed',
								zIndex: 9999,
								left: 0,
								top: 0,
								'-webkit-backface-visibility': 'hidden'
							},
							t = 'transition';

						cssObj['-webkit-'+t] = cssObj['-moz-'+t] = cssObj['-o-'+t] = cssObj[t] = transition;

						newImg.css(cssObj);
						return newImg;
					},
					showMainContent = function() {
						mfp.content.css('visibility', 'visible');
					},
					openTimeout,
					animatedImg;

				_mfpOn('BuildControls'+ns, function() {
					if(mfp._allowZoom()) {

						clearTimeout(openTimeout);
						mfp.content.css('visibility', 'hidden');

						// Basically, all code below does is clones existing image, puts in on top of the current one and animated it

						image = mfp._getItemToZoom();

						if(!image) {
							showMainContent();
							return;
						}

						animatedImg = getElToAnimate(image);

						animatedImg.css( mfp._getOffset() );

						mfp.wrap.append(animatedImg);

						openTimeout = setTimeout(function() {
							animatedImg.css( mfp._getOffset( true ) );
							openTimeout = setTimeout(function() {

								showMainContent();

								setTimeout(function() {
									animatedImg.remove();
									image = animatedImg = null;
									_mfpTrigger('ZoomAnimationEnded');
								}, 16); // avoid blink when switching images

							}, duration); // this timeout equals animation duration

						}, 16); // by adding this timeout we avoid short glitch at the beginning of animation


						// Lots of timeouts...
					}
				});
				_mfpOn(BEFORE_CLOSE_EVENT+ns, function() {
					if(mfp._allowZoom()) {

						clearTimeout(openTimeout);

						mfp.st.removalDelay = duration;

						if(!image) {
							image = mfp._getItemToZoom();
							if(!image) {
								return;
							}
							animatedImg = getElToAnimate(image);
						}


						animatedImg.css( mfp._getOffset(true) );
						mfp.wrap.append(animatedImg);
						mfp.content.css('visibility', 'hidden');

						setTimeout(function() {
							animatedImg.css( mfp._getOffset() );
						}, 16);
					}

				});

				_mfpOn(CLOSE_EVENT+ns, function() {
					if(mfp._allowZoom()) {
						showMainContent();
						if(animatedImg) {
							animatedImg.remove();
						}
						image = null;
					}
				});
			},

			_allowZoom: function() {
				return mfp.currItem.type === 'image';
			},

			_getItemToZoom: function() {
				if(mfp.currItem.hasSize) {
					return mfp.currItem.img;
				} else {
					return false;
				}
			},

			// Get element postion relative to viewport
			_getOffset: function(isLarge) {
				var el;
				if(isLarge) {
					el = mfp.currItem.img;
				} else {
					el = mfp.st.zoom.opener(mfp.currItem.el || mfp.currItem);
				}

				var offset = el.offset();
				var paddingTop = parseInt(el.css('padding-top'),10);
				var paddingBottom = parseInt(el.css('padding-bottom'),10);
				offset.top -= ( $(window).scrollTop() - paddingTop );


				/*

				 Animating left + top + width/height looks glitchy in Firefox, but perfect in Chrome. And vice-versa.

				 */
				var obj = {
					width: el.width(),
					// fix Zepto height+padding issue
					height: (_isJQ ? el.innerHeight() : el[0].offsetHeight) - paddingBottom - paddingTop
				};

				// I hate to do this, but there is no another option
				if( getHasMozTransform() ) {
					obj['-moz-transform'] = obj['transform'] = 'translate(' + offset.left + 'px,' + offset.top + 'px)';
				} else {
					obj.left = offset.left;
					obj.top = offset.top;
				}
				return obj;
			}

		}
	});



	/*>>zoom*/

	/*>>iframe*/

	var IFRAME_NS = 'iframe',
		_emptyPage = '//about:blank',

		_fixIframeBugs = function(isShowing) {
			if(mfp.currTemplate[IFRAME_NS]) {
				var el = mfp.currTemplate[IFRAME_NS].find('iframe');
				if(el.length) {
					// reset src after the popup is closed to avoid "video keeps playing after popup is closed" bug
					if(!isShowing) {
						el[0].src = _emptyPage;
					}

					// IE8 black screen bug fix
					if(mfp.isIE8) {
						el.css('display', isShowing ? 'block' : 'none');
					}
				}
			}
		};

	$.magnificPopup.registerModule(IFRAME_NS, {

		options: {
			markup: '<div class="mfp-iframe-scaler">'+
				'<div class="mfp-close"></div>'+
				'<iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe>'+
				'</div>',

			srcAction: 'iframe_src',

			// we don't care and support only one default type of URL by default
			patterns: {
				youtube: {
					index: 'youtube.com',
					id: 'v=',
					src: '//www.youtube.com/embed/%id%?autoplay=1'
				},
				vimeo: {
					index: 'vimeo.com/',
					id: '/',
					src: '//player.vimeo.com/video/%id%?autoplay=1'
				},
				gmaps: {
					index: '//maps.google.',
					src: '%id%&output=embed'
				}
			}
		},

		proto: {
			initIframe: function() {
				mfp.types.push(IFRAME_NS);

				_mfpOn('BeforeChange', function(e, prevType, newType) {
					if(prevType !== newType) {
						if(prevType === IFRAME_NS) {
							_fixIframeBugs(); // iframe if removed
						} else if(newType === IFRAME_NS) {
							_fixIframeBugs(true); // iframe is showing
						}
					}// else {
					// iframe source is switched, don't do anything
					//}
				});

				_mfpOn(CLOSE_EVENT + '.' + IFRAME_NS, function() {
					_fixIframeBugs();
				});
			},

			getIframe: function(item, template) {
				var embedSrc = item.src;
				var iframeSt = mfp.st.iframe;

				$.each(iframeSt.patterns, function() {
					if(embedSrc.indexOf( this.index ) > -1) {
						if(this.id) {
							if(typeof this.id === 'string') {
								embedSrc = embedSrc.substr(embedSrc.lastIndexOf(this.id)+this.id.length, embedSrc.length);
							} else {
								embedSrc = this.id.call( this, embedSrc );
							}
						}
						embedSrc = this.src.replace('%id%', embedSrc );
						return false; // break;
					}
				});

				var dataObj = {};
				if(iframeSt.srcAction) {
					dataObj[iframeSt.srcAction] = embedSrc;
				}
				mfp._parseMarkup(template, dataObj, item);

				mfp.updateStatus('ready');

				return template;
			}
		}
	});



	/*>>iframe*/

	/*>>gallery*/
	/**
	 * Get looped index depending on number of slides
	 */
	var _getLoopedId = function(index) {
			var numSlides = mfp.items.length;
			if(index > numSlides - 1) {
				return index - numSlides;
			} else  if(index < 0) {
				return numSlides + index;
			}
			return index;
		},
		_replaceCurrTotal = function(text, curr, total) {
			return text.replace(/%curr%/gi, curr + 1).replace(/%total%/gi, total);
		};

	$.magnificPopup.registerModule('gallery', {

		options: {
			enabled: false,
			arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',
			preload: [0,2],
			navigateByImgClick: true,
			arrows: true,

			tPrev: 'Previous (Left arrow key)',
			tNext: 'Next (Right arrow key)',
			tCounter: '%curr% of %total%'
		},

		proto: {
			initGallery: function() {

				var gSt = mfp.st.gallery,
					ns = '.mfp-gallery',
					supportsFastClick = Boolean($.fn.mfpFastClick);

				mfp.direction = true; // true - next, false - prev

				if(!gSt || !gSt.enabled ) return false;

				_wrapClasses += ' mfp-gallery';

				_mfpOn(OPEN_EVENT+ns, function() {

					if(gSt.navigateByImgClick) {
						mfp.wrap.on('click'+ns, '.mfp-img', function() {
							if(mfp.items.length > 1) {
								mfp.next();
								return false;
							}
						});
					}

					_document.on('keydown'+ns, function(e) {
						if (e.keyCode === 37) {
							mfp.prev();
						} else if (e.keyCode === 39) {
							mfp.next();
						}
					});
				});

				_mfpOn('UpdateStatus'+ns, function(e, data) {
					if(data.text) {
						data.text = _replaceCurrTotal(data.text, mfp.currItem.index, mfp.items.length);
					}
				});

				_mfpOn(MARKUP_PARSE_EVENT+ns, function(e, element, values, item) {
					var l = mfp.items.length;
					values.counter = l > 1 ? _replaceCurrTotal(gSt.tCounter, item.index, l) : '';
				});

				_mfpOn('BuildControls' + ns, function() {
					if(mfp.items.length > 1 && gSt.arrows && !mfp.arrowLeft) {
						var markup = gSt.arrowMarkup,
							arrowLeft = mfp.arrowLeft = $( markup.replace(/%title%/gi, gSt.tPrev).replace(/%dir%/gi, 'left') ).addClass(PREVENT_CLOSE_CLASS),
							arrowRight = mfp.arrowRight = $( markup.replace(/%title%/gi, gSt.tNext).replace(/%dir%/gi, 'right') ).addClass(PREVENT_CLOSE_CLASS);

						var eName = supportsFastClick ? 'mfpFastClick' : 'click';
						arrowLeft[eName](function() {
							mfp.prev();
						});
						arrowRight[eName](function() {
							mfp.next();
						});

						// Polyfill for :before and :after (adds elements with classes mfp-a and mfp-b)
						if(mfp.isIE7) {
							_getEl('b', arrowLeft[0], false, true);
							_getEl('a', arrowLeft[0], false, true);
							_getEl('b', arrowRight[0], false, true);
							_getEl('a', arrowRight[0], false, true);
						}

						mfp.container.append(arrowLeft.add(arrowRight));
					}
				});

				_mfpOn(CHANGE_EVENT+ns, function() {
					if(mfp._preloadTimeout) clearTimeout(mfp._preloadTimeout);

					mfp._preloadTimeout = setTimeout(function() {
						mfp.preloadNearbyImages();
						mfp._preloadTimeout = null;
					}, 16);
				});


				_mfpOn(CLOSE_EVENT+ns, function() {
					_document.off(ns);
					mfp.wrap.off('click'+ns);

					if(mfp.arrowLeft && supportsFastClick) {
						mfp.arrowLeft.add(mfp.arrowRight).destroyMfpFastClick();
					}
					mfp.arrowRight = mfp.arrowLeft = null;
				});

			},
			next: function() {
				mfp.direction = true;
				mfp.index = _getLoopedId(mfp.index + 1);
				mfp.updateItemHTML();
			},
			prev: function() {
				mfp.direction = false;
				mfp.index = _getLoopedId(mfp.index - 1);
				mfp.updateItemHTML();
			},
			goTo: function(newIndex) {
				mfp.direction = (newIndex >= mfp.index);
				mfp.index = newIndex;
				mfp.updateItemHTML();
			},
			preloadNearbyImages: function() {
				var p = mfp.st.gallery.preload,
					preloadBefore = Math.min(p[0], mfp.items.length),
					preloadAfter = Math.min(p[1], mfp.items.length),
					i;

				for(i = 1; i <= (mfp.direction ? preloadAfter : preloadBefore); i++) {
					mfp._preloadItem(mfp.index+i);
				}
				for(i = 1; i <= (mfp.direction ? preloadBefore : preloadAfter); i++) {
					mfp._preloadItem(mfp.index-i);
				}
			},
			_preloadItem: function(index) {
				index = _getLoopedId(index);

				if(mfp.items[index].preloaded) {
					return;
				}

				var item = mfp.items[index];
				if(!item.parsed) {
					item = mfp.parseEl( index );
				}

				_mfpTrigger('LazyLoad', item);

				if(item.type === 'image') {
					item.img = $('<img class="mfp-img" />').on('load.mfploader', function() {
						item.hasSize = true;
					}).on('error.mfploader', function() {
						item.hasSize = true;
						item.loadError = true;
						_mfpTrigger('LazyLoadError', item);
					}).attr('src', item.src);
				}


				item.preloaded = true;
			}
		}
	});

	/*
	 Touch Support that might be implemented some day

	 addSwipeGesture: function() {
	 var startX,
	 moved,
	 multipleTouches;

	 return;

	 var namespace = '.mfp',
	 addEventNames = function(pref, down, move, up, cancel) {
	 mfp._tStart = pref + down + namespace;
	 mfp._tMove = pref + move + namespace;
	 mfp._tEnd = pref + up + namespace;
	 mfp._tCancel = pref + cancel + namespace;
	 };

	 if(window.navigator.msPointerEnabled) {
	 addEventNames('MSPointer', 'Down', 'Move', 'Up', 'Cancel');
	 } else if('ontouchstart' in window) {
	 addEventNames('touch', 'start', 'move', 'end', 'cancel');
	 } else {
	 return;
	 }
	 _window.on(mfp._tStart, function(e) {
	 var oE = e.originalEvent;
	 multipleTouches = moved = false;
	 startX = oE.pageX || oE.changedTouches[0].pageX;
	 }).on(mfp._tMove, function(e) {
	 if(e.originalEvent.touches.length > 1) {
	 multipleTouches = e.originalEvent.touches.length;
	 } else {
	 //e.preventDefault();
	 moved = true;
	 }
	 }).on(mfp._tEnd + ' ' + mfp._tCancel, function(e) {
	 if(moved && !multipleTouches) {
	 var oE = e.originalEvent,
	 diff = startX - (oE.pageX || oE.changedTouches[0].pageX);

	 if(diff > 20) {
	 mfp.next();
	 } else if(diff < -20) {
	 mfp.prev();
	 }
	 }
	 });
	 },
	 */


	/*>>gallery*/

	/*>>retina*/

	var RETINA_NS = 'retina';

	$.magnificPopup.registerModule(RETINA_NS, {
		options: {
			replaceSrc: function(item) {
				return item.src.replace(/\.\w+$/, function(m) { return '@2x' + m; });
			},
			ratio: 1 // Function or number.  Set to 1 to disable.
		},
		proto: {
			initRetina: function() {
				if(window.devicePixelRatio > 1) {

					var st = mfp.st.retina,
						ratio = st.ratio;

					ratio = !isNaN(ratio) ? ratio : ratio();

					if(ratio > 1) {
						_mfpOn('ImageHasSize' + '.' + RETINA_NS, function(e, item) {
							item.img.css({
								'max-width': item.img[0].naturalWidth / ratio,
								'width': '100%'
							});
						});
						_mfpOn('ElementParse' + '.' + RETINA_NS, function(e, item) {
							item.src = st.replaceSrc(item, ratio);
						});
					}
				}

			}
		}
	});

	/*>>retina*/

	/*>>fastclick*/
	/**
	 * FastClick event implementation. (removes 300ms delay on touch devices)
	 * Based on https://developers.google.com/mobile/articles/fast_buttons
	 *
	 * You may use it outside the Magnific Popup by calling just:
	 *
	 * $('.your-el').mfpFastClick(function() {
 *     console.log('Clicked!');
 * });
	 *
	 * To unbind:
	 * $('.your-el').destroyMfpFastClick();
	 *
	 *
	 * Note that it's a very basic and simple implementation, it blocks ghost click on the same element where it was bound.
	 * If you need something more advanced, use plugin by FT Labs https://github.com/ftlabs/fastclick
	 *
	 */

	(function() {
		var ghostClickDelay = 1000,
			supportsTouch = 'ontouchstart' in window,
			unbindTouchMove = function() {
				_window.off('touchmove'+ns+' touchend'+ns);
			},
			eName = 'mfpFastClick',
			ns = '.'+eName;


		// As Zepto.js doesn't have an easy way to add custom events (like jQuery), so we implement it in this way
		$.fn.mfpFastClick = function(callback) {

			return $(this).each(function() {

				var elem = $(this),
					lock;

				if( supportsTouch ) {

					var timeout,
						startX,
						startY,
						pointerMoved,
						point,
						numPointers;

					elem.on('touchstart' + ns, function(e) {
						pointerMoved = false;
						numPointers = 1;

						point = e.originalEvent ? e.originalEvent.touches[0] : e.touches[0];
						startX = point.clientX;
						startY = point.clientY;

						_window.on('touchmove'+ns, function(e) {
							point = e.originalEvent ? e.originalEvent.touches : e.touches;
							numPointers = point.length;
							point = point[0];
							if (Math.abs(point.clientX - startX) > 10 ||
								Math.abs(point.clientY - startY) > 10) {
								pointerMoved = true;
								unbindTouchMove();
							}
						}).on('touchend'+ns, function(e) {
							unbindTouchMove();
							if(pointerMoved || numPointers > 1) {
								return;
							}
							lock = true;
							e.preventDefault();
							clearTimeout(timeout);
							timeout = setTimeout(function() {
								lock = false;
							}, ghostClickDelay);
							callback();
						});
					});

				}

				elem.on('click' + ns, function() {
					if(!lock) {
						callback();
					}
				});
			});
		};

		$.fn.destroyMfpFastClick = function() {
			$(this).off('touchstart' + ns + ' click' + ns);
			if(supportsTouch) _window.off('touchmove'+ns+' touchend'+ns);
		};
	})();

	/*>>fastclick*/
	_checkInstance(); })(window.jQuery || window.Zepto);
/*jslint browser: true, indent: 4, regexp: true, white:true */
/**
 * Cookie class
 * Handles all operations on cookies
 *
 * @author Johan Arensman
 */
(function (global) {
	'use strict';

	/**
	 * Creates a new cookie instance with the given name.
	 * @param {string} name
	 * @param {Object|string} [newValue] (new) value for this cookie or object literal with options.
	 * @constructor
	 */
	function Cookie(name, newValue) {
		if (name !== undefined) {
			this.name = name;

			if (newValue !== undefined) {
				if (typeof newValue === 'object') {
					this.set(newValue);
				} else {
					this.setValue(newValue);
				}
			} else {
				this.read();
			}
		}
	}

	/**
	 * Return the names of all cookies
	 * return {array} An array with all cookie names.
	 */
	function names() {
		return document.cookie.replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, "")
			.split(/\s*(?:=[^;]*)?;\s*/);
	}

	/**
	 * Returns an object literal with cookie names and Cookie instances for all cookies.
	 * @returns {Object}
	 */
	function all() {
		var keys = names(),
			i = 0, l, cookies = {};
		for (l = keys.length; i < l; i++) {
			cookies[keys[i]] = new Cookie(keys[i]);
		}
		return cookies;
	}

	Cookie.names = names;
	Cookie.all = all;

	Cookie.prototype = {
		'name': undefined,
		'value': undefined,
		'domain': undefined,
		'path': undefined,
		'expires': undefined,
		'max-age': undefined,
		'secure': undefined,

		'names': names,
		'all': all,

		/**
		 * Sets the value of this cookie
		 * @param {*} value
		 * @returns {Cookie}
		 */
		setValue: function (value) {
			this.value = window.encodeURIComponent(value);
			return this;
		},

		/**
		 * Set the expiration date by days
		 * @param {Number} days
		 * @returns {Cookie}
		 */
		setDays: function (days) {
			var date;
			if (days) {
				date = new Date();
				date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
				this.expires = date;
			}
			return this;
		},

		/**
		 * Set any valid cookie property either using an object with key/value pairs or a property with a value.
		 * @param {string|Object} option The name of the option or the object containing key/value pairs.
		 * @param {*} [value] The value of the option
		 * @returns {Cookie}
		 */
		set: function (option, value) {
			var setter = typeof option === 'string' ? 'set' + (option.charAt(0).toUpperCase() + option.substring(1)) : false,
				key;

			if (typeof this[setter] === 'function') {
				return this[setter](value);
			}

			if (this.hasOwnProperty(option)) {
				this[option] = value;
			} else {
				for (key in option) {
					if (option.hasOwnProperty(key) && this.hasOwnProperty(key)) {
						this.set(key, option[key]);
					}
				}
			}
			return this;
		},

		/**
		 * Reads the value of this cookie
		 * @returns {string|*}
		 */
		read: function () {
			if (typeof this.name !== 'string') {
				throw new TypeError("No name was set for the cookie.");
			}
			this.value = document.cookie.replace(new RegExp('(?:(?:^|.*;\s*)'
				+ this.name + '\s*=\s*([^;]*).*$)|^.*$', 'g'), '$1');
			return window.decodeURIComponent(this.value);
		},

		/**
		 * Write / save the cookie
		 * @param {string|Object} [value]
		 * @returns {Cookie}
		 */
		write: function (value) {
			var maxAge = window.parseInt(this['max-age']),
				cookie;

			if (value !== undefined) {
				this.setValue(value);
			}

			if (typeof this.name !== 'string') {
				throw new TypeError("No name was set for the cookie.");
			}

			cookie = [this.name + '=' + this.value];

			if (this.expires) {
				if (!this.expires instanceof Date) {
					throw new TypeError("Expires property must be an instance of Date.");
				}
				cookie.push('expires=' + this.expires.toUTCString());
			}

			if (maxAge) {
				cookie.push('max-age=' + maxAge);
			}

			if (this.path) {
				cookie.push('path=' + this.path);
			}

			document.cookie = cookie.join('; ');
			return this;
		},

		/**
		 * Remove the cookie
		 * @returns {Cookie}
		 */
		remove: function () {
			this.setDays(-1);
			return this.write('');
		},

		/**
		 * Returns the string value of the cookie
		 * @returns {string}
		 */
		toString: function () {
			return String(this.value);
		}
	};

	window[global] = Cookie;
}('Cookie'));

/*jslint browser: true, indent: 4, white:true */

/**
 * Create an internationalisation object automatically set to the language used on this document.
 * @author Johan Arensman
 */
var i18n = (function (language) {
	'use strict';
	var catalogs = {},
		defaultLanguage = language ? language.toLowerCase() : 'en',
		cache = {};

	/**
	 * Returns the catalog value for the given dot separated key.
	 * @param {string} key Dot separated path to the requested string without the language key.
	 * @param {string} [language] Optional override for the language to find.
	 * @returns {*} The result matching the given key or false when it's not found.
	 */
	function translate(key, language) {
		var value = catalogs,
			path, part;

		if (cache.hasOwnProperty(key)) {
			return cache[key];
		}

		path = key.split('.');
		path.unshift(language || defaultLanguage);

		do {
			part = path.shift();
			value = value.hasOwnProperty(part) ? value[part] : false;
		} while (value && path.length);

		cache[key] = value;
		return value;
	}

	/**
	 * Loads a formatted object as translations used in the application
	 * @param {object} translations
	 */
	function loadTranslations(translations) {
		catalogs = translations;
	}

	return {
		'get': translate,
		'loadTranslations': loadTranslations
	};
}(document.documentElement.getAttribute('lang') || 'en'));

﻿﻿$(document).ready(function () {

    $.fn.trackTrace = function () {
        var tracktraceData = [],
            that = this,
            url,
            isBusy = false,
            countriesRendered = false,
            formClicked = false,
            startForm = $('form#tracktrace'),
            activeCode = false,
            postalLoad = false,
            formKeys = {
                barcode: startForm.find('input#barcode').attr('name'),
                country: 'tracktrace-country',
                postal: startForm.find('input#postalcode').attr('name'),
                foreign: startForm.find('input#foreign').attr('name'),
                link: startForm.attr('action')
            },
            countries = [];



        function initCountries() {
            var trackTraceExists = $('article.track-trace');

            if (countries.length == 0 && trackTraceExists.length > 0) {
                $(document).ajaxStart(function() {
                    trackTraceExists.addClass('loading');
                });
                $(document).ajaxStop(function() {
                    trackTraceExists.removeClass('loading');
                    $(that).trigger('updateSize.killerApp');
                    $(document).on('unbind', 'ajaxStart');
                });

                $.ajax({
                    dataType: 'json',
                    url: $('article.track-trace').data('countries'),
                    async: true,
                    success: function (data) {
                        if (data != null) {
                            var firstOption;
                            $.each(data, function (key, value) {
                                countries.push(value);
                            });

                            countries.sort(predicate(
                                'selected', 'frequent', 'value'));
                        }
                        renderCountries();
                    }
                });

                $.each(countries, function (key, val) {
                    if (val.postal && val.selected == 'asc') {
                        var postalCode = $('form#tracktrace').find('div.postal-code');
                        postalCode.removeClass('hidden');
                    }
                });
            }

            function predicate() {
                var fields = [],
                  n_fields = arguments.length,
                  field, name, reverse, cmp;

                var default_cmp = function (a, b) {
                    if (a === b) return 0;
                    return a < b ? -1 : 1;
                },
                  getCmpFunc = function (primer, reverse) {
                      var dfc = default_cmp,
                        // closer in scope
                        cmp = default_cmp;
                      if (primer) {
                          cmp = function (a, b) {
                              return dfc(primer(a), primer(b));
                          };
                      }
                      if (reverse) {
                          return function (a, b) {
                              return -1 * cmp(a, b);
                          };
                      }
                      return cmp;
                  };

                // preprocess sorting options
                for (var i = 0; i < n_fields; i++) {
                    field = arguments[i];
                    if (typeof field === 'string') {
                        name = field;
                        cmp = default_cmp;
                    } else {
                        name = field.name;
                        cmp = getCmpFunc(field.primer, field.reverse);
                    }
                    fields.push({
                        name: name,
                        cmp: cmp
                    });
                }

                // final comparison function
                return function (A, B) {
                    var a, b, name, result;
                    for (var i = 0; i < n_fields; i++) {
                        result = 0;
                        field = fields[i];
                        name = field.name;

                        result = field.cmp(A[name], B[name]);
                        if (result !== 0) break;
                    }
                    return result;
                };
            }
        }

        if ($('.killerapp-open-wrapper').has($('article.track-trace')).length > 0) {
            formClicked = true;
            initCountries();
        }

        $('form#tracktrace').on('submit', function () {
            url = changeCodeUrl($(this).attr('action'), $(this));
            var countrySelect = $('select#tracktrace-country');
            var countryCode = countrySelect.find('option:selected').data('countrycode');
            var barcode = $('input#barcode').val();
            var postalcode = $('input#postalcode').val();
            if (countryCode == '') {
                countryCode = 'EN';
            }
            document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
                detail: {
                    name: "funnel_interaction",
                    funnel: {
                        "name": "killer widget - track en trace",
                        "technology": "killerwidget",
                        "type": "application",
                        "step": "laatste",
                        "step_name": "succes killerwidget"
                    },
                    optins: [
                        {
                            "category": "barcode",
                            "answer": barcode
                        },
                        {
                            "category": "postalcode",
                            "answer": postalcode
                        },
                        {
                            "category": "country",
                            "answer": countryCode
                        }
                    ]
                }
            })
            );
            if (activeCode.formMethod == 'Get (url)') {
                if (activeCode != false) {
                    url = changeCodeUrl(activeCode.link, $(this));
                } else {
                    url = changeCodeUrl($(this).attr('action'), $(this));
                }
                var newUrl = url.split('{1}').join($('input#barcode').val()).split('{2}').join($('input#postalcode').val()).split('{3}').join($('select#tracktrace-country').val()).split('{4}').join(countryCode);
                if (newUrl != '') {
                    window.open(newUrl, '_blank');
                }
                return false;
            }
            if (activeCode == false) {
                url = changeCodeUrl($(this).attr('action'), $(this));
                var newUrl = url.split('{1}').join($('input#barcode').val()).split('{2}').join($('input#postalcode').val()).split('{3}').join($('select#tracktrace-country').val()).split('{4}').join(countryCode);
                if (newUrl != '') {
                    window.open(newUrl, '_blank');
                }
                return false;
            }
        });

        $(this).on('click open.killerApp', function (key, value) {
            var form = $('form#tracktrace');

            if (!formClicked && !countriesRendered) {
                formClicked = true;
                if (form.find('.tracktrace-country').length) {
                    initCountries();
                }
            }

            // Get data service URL
            var url = $(this).data('url');

            // Resolving data.
            if (tracktraceData.length < 1) {
                $.ajax({
                    dataType: 'json',
                    url: url,
                    async: true,
                    success: function (data) {
                        tracktraceData = data;
                    }
                });
            }
        });
        if (typeof ($(this).find('input#postalcode')) !== 'undefined') {
            var button = $('form#tracktrace').find('div.submit-buttons button');
            var postalField = $(this).find('input#postalcode');
            var barcodeField = $(this).find('input#barcode');
            $(postalField).on('keyup change', function () {
                if (postalField.val().length > 0 && barcodeField.val().length > 0) {
                    button.attr('disabled', false);
                } else {
                    button.attr('disabled', true);
                }
            });
        }

        if (typeof ($(this).find('input#barcode')) !== 'undefined') {
            var barcodeField = $(this).find('input#barcode');
            $(barcodeField).on('keyup change', function () {
                var button = $('form#tracktrace').find('div.submit-buttons button');
                var postalCode = $('form#tracktrace').find('div.postal-code');
                if (postalCode.css('display') == 'block') {
                    if (barcodeField.val().length > 0 && postalCode.find('input#postalcode').val().length > 0) {
                        button.attr('disabled', false);
                    } else {
                        button.attr('disabled', true);
                    }
                } else {
                    if (barcodeField.val().length > 0) {
                        button.attr('disabled', false);
                    } else {
                        button.attr('disabled', true);
                    }
                }

                if (!isBusy) {
                    isBusy = true;
                    var code = matchPrefix($(this).val());
                    if (code !== false) {
                        activeCode = code;
                        setBarcodeValues(code);
                    } else {
                        activeCode = false;
                        resetFormKeys();
                    }

                } else {
                    todo = $(this).val();
                }
            });
        }

        function matchPrefix(barcode) {
            for (var keyword in tracktraceData) {
                var data = tracktraceData[keyword];
                if (data.title != null) {
                    var patterns = getRegexTypes(data.regextype, data.prefix);
                    for (var pattern in patterns) {
                        for (var i = 0; i < patterns.length; i++) {
                            if (barcode.match(patterns[i])) {
                                isBusy = false;
                                return tracktraceData[keyword];
                            }
                        }
                    }
                }
            }
            isBusy = false;
            return false;
        }

        function setBarcodeValues(code) {
            var form = $('form#tracktrace');
            if (code.formMethod == 'Get (url)') {
                //code.link = changeCodeUrl(code.link, form);
                url = code.link;
            } else if (code.formMethod == 'Post') {
                form.attr('method', 'POST');
                if (code.barcodeKey != '') { form.find('input#barcode').attr('name', code.barcodeKey); }
                if (code.countryKey != '') { form.find('select#tracktrace-country').attr('name', code.countryKey); }
                if (code.postalKey != '') { form.find('input#postalcode').attr('name', code.postalKey); }
                if (code.foreignKey != '') { form.find('input#foreign').attr('name', code.foreignKey); }
                if (code.link != '') { form.attr('action', code.link); }
            }
        } 1

        function changeCodeUrl(url, form) {
            if (form.find('div.form-row.postal-code').hasClass('hidden') || form.find('input#postalcode').val() == '') {
                var postal = url.split("?");
                var postal = postal[postal.length - 1].split('&');
                if (postal.length < 2) {
                    url = url.replace('/{2}', '');
                }
                else if (postal.length > 1) {
                    for (var i = 0; i < postal.length; i++) {
                        if (postal[i].indexOf('{2}') > -1) {
                            url = url.replace('&' + postal[i], '');
                            url = url.replace(postal[i], '');
                        }
                    }
                }
            }
            if (form.find('select#tracktrace-country').val() == '') {
                var country = url.split("?");
                var country = country[country.length - 1].split('&');
                if (country.length < 2) {
                    url = url.replace('/{3}', '');
                }
                else if (country.length > 1) {
                    for (var i = 0; i < postal.length; i++) {
                        if (postal[i].indexOf('{3}') > -1) {
                            url = url.replace('&' + postal[i], '');
                            url = url.replace(postal[i], '');
                        }
                    }
                }
            }
            return url;
        }

        function resetFormKeys() {
            var form = $('form#tracktrace');
            form.attr('method', 'GET');
            form.find('input#barcode').attr('name', formKeys.barcode);
            form.find('select#tracktrace-country').attr('name', formKeys.country);
            form.find('input#postalcode').attr('name', formKeys.postal);
            form.find('input#foreign').attr('name', formKeys.foreign);
            form.attr('action', formKeys.link);

            return true;
        }


        function getRegexTypes(regexType, prefix) {
            var ret = [];

            if (regexType == "3S" || regexType == "2S") {
                ret.push(new RegExp('\\b' + prefix + '+[a-zA-Z]{1,6}[0-9]{2,10}\\b', 'gi'));
            }
            if (regexType == "KG") {
                ret.push(new RegExp('\\b' + prefix + '+[0-9]{1,9}\\b', 'gi'));
                ret.push(new RegExp('\\b' + prefix + '+[a-zA-Z]{1,6}[0-9]{2,10}\\b', 'gi'));
            }
            if (regexType == "Brieven internationaal" || regexType == "Pakketten internationaal") {
                ret.push(new RegExp('\\b' + prefix + '+[0-9]{5,9}[a-zA-Z]{2,3}\\b', 'gi'));
            }

            if (regexType == "Alleen code prefix") {
                ret.push(new RegExp('\\b' + prefix + '[a-zA-Z0-9]{1,20}\\b', 'gi'));
            }
            1
            if (ret.length == 0) {
                ret.push(new RegExp('\\b' + prefix + '+[a-zA-Z0-9]{1,11}\\b', 'gi'));
            }


            return ret;
        }

        function renderCountries() {
            var options = [];

            var select = $('<select>', {
                'class': 'inputselect',
                'name': formKeys.country,
                'id': 'tracktrace-country'
            }).on('change', function () {
                var inputPostal = $('div.form-row.postal-code');
                var button = $('form#tracktrace').find('div.submit-buttons button');
                var postalCode = $('form#tracktrace').find('div.postal-code');
                if ($(this.options[this.selectedIndex]).attr('data-postal') == 'true') {
                    if (postalCode.find('input#postalcode').val().length > 0) {
                        button.attr('disabled', false);
                    } else {
                        button.attr('disabled', true);
                    }
                    inputPostal.removeClass('hidden');
                } else {
                    var barcodeField = $('form#tracktrace').find('input#barcode');
                    if (barcodeField.val().length > 0) {
                        button.attr('disabled', false);
                    } else {
                        button.attr('disabled', true);
                    }
                    inputPostal.addClass('hidden');
                }
            });

            select.append($.map(countries, function (country) {
                if (country.key == "separator") {
                    return option = $('<option>', {
                        'value': "",
                        'text': "",
                        'disabled': true,
                        'class': 'separator'
                    });
                }
                return option = $('<option>', {
                    'value': country.key,
                    'text': country.value,
                    'data-postal': country.postal,
                    'data-countrycode': country.countryCode,
                    'selected': function () {
                        if (country.selected == "asc") {
                            postalLoad = country.postal;
                            return true;
                        }
                    }
                });
            }));

            $('.tracktrace-country').append(select);
            countriesRendered = true;
            if (postalLoad) {
                var postalCode = $('form#tracktrace').find('div.postal-code');
                postalCode.removeClass('hidden');
                $(that).trigger('updateSize.killerApp');
            }

        }
    };

    $('article.track-trace').trackTrace();

    // Deprecated funciton for 3s code.
    $('#link-tracktrace').on('click', function () {
        // Modify Url when one of theses prefixes are used.
        var catchForeign = ['3S', 'KG', '2S'];

        // Get prefix of code.
        var prefix = $('#barcode').val().substring(0, 2);

        // If prefix is in array.
        var used = $.inArray(prefix.toUpperCase(), catchForeign) > -1;

        // Get current url.
        currentUrl = $(this).attr('href').toLowerCase().replace("barcode", "b").replace("postalcode", "p");

        // Get foreign value.
        var foreign = $('input[name="i"]:checked').val();

        // Get postalcode value.
        var postalCode = $('#postalcode').val();

        // If postalcode is not empty and foreign is false.
        if (postalCode != "" && foreign == 'False') {
            currentUrl = currentUrl.replace("p=", "p=" + postalCode);
        }

        // When search value is used with 3s, kg or 2s prefix
        if (used) {
            if (foreign == '') {
                foreign = 'False';
            }
            currentUrl += '&i=' + foreign;
            if (foreign == 'True') {
                currentUrl = currentUrl.replace("&p=", "");
            }
        }
        window.open(currentUrl);
        return false;
    });

      $('.track-trace').one('keyup', ':input:visible:first', function () {
          document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
              detail: {
                  name: "funnel_interaction",
                  funnel: {
                      "name": "killer widget - track en trace",      
                      "technology": "killerwidget",
                      "type": "application",
                      "step": "10",
                      "step_name": "start killerwidget"
                  }
              }
          })
          );
      });

});

/*jslint browser: true, plusplus: true, regexp: true, indent: 4, white:true */
/*global Modernizr, jQuery, i18n */

jQuery(function ($) {
	'use strict';

    /**
	 * Generic killer app
	 * @param {object} [options]
	 * @returns {jQuery}
	 */
	$.fn.killerApp = function (options) {
		var $html = $(document.documentElement),
			desktopWidth = 1000,
			killerApps = $(this),
			settings = $.extend({}, {
				onActivate: $.noop,
				onDeactivate: $.noop
			}, options),
			activeApp;

		window.addEventListener('resize', setAppLocation);

		function setAppLocation() {
			var width = window.innerWidth;
			var container = $('.banner-tt');
			if (width > desktopWidth) {
				container.prependTo($('.killerapp-banner'));
			} else {
				// Only switch if container is still in desktop mode
				// otherwise the switch is done from mobile to mobile which is
				// unnecessary(and caused keyboard errors on android)
				if (container.parent('.killerapp-banner').length) {
					container.prependTo($('.killerapp-banner-loose'));
				}
			}
		}
		setAppLocation();

		return killerApps
			.each(function () {
				var element = $(this),
					form = element.find('form'),
					collapsed = true;

				element
					.on('open.killerApp', function () {
						if (collapsed) {
							element.addClass('opening').removeClass('collapsed');
							killerApps.not(element).trigger('close.killerApp');
							form.show();
							collapsed = false;
							activeApp = element;
							if (!element.hasClass('is-ratescalculator')) {
								settings.onActivate();
							}
						}
					})
					.on('close.killerApp', function () {
						if (!collapsed) {
							if (!element.hasClass('is-ratescalculator')) {
								element.addClass('collapsed closing');
							} else {
								element.addClass('closing');
							}
							form.hide();
							collapsed = true;
							activeApp = null;
							settings.onDeactivate();
						}
					});

				// header is a 'open':
				element.find('header').on('click', function () {
					element.trigger('open.killerApp');
				});

				// make sure initially open killer app is initialized
				if (!element.is('.collapsed')) {
					element.trigger('open.killerApp');
					checkInputText($(this).find('form'));
				}

				element.find('header').on('click', function () {
					// Focus at the first empty input text field. 
					checkInputText($(this).next('form'));
				});
			});
	};

	// Set focus to first empty input field.
	var checkInputText = function (form) {
		var ret = "";
		form.find('input[type=text]').each(function (key, value) {
			if ($(this).val() == "" && ret == "") {
				ret = this;
			}
		});
		if (ret == "") {
			ret = form.find('input[type=text]').last();
		}
		$(ret).focus();
	};
});

/*jslint browser: true, plusplus: true, regexp: true, indent: 4, white:true */
/*global Modernizr, jQuery, i18n */

jQuery(function ($) {
    'use strict';

    /**
	 * Generic killer app
	 * @param {object} [options]
	 * @returns {jQuery}
	 */
    $.fn.killerAppOld = function (options) {
        var $html = $(document.documentElement),
            desktopWidth = 1000,
			killerApps = $(this),
			settings = $.extend({}, {
			    onActivate: $.noop,
			    onDeactivate: $.noop
			}, options),
			activeAppClick = false,
			activeApp;

        $html
			// check if the active app should be deactivated:
			.on('click touchend', function () {
			    if (activeApp && !activeAppClick) {
			        activeApp.trigger('close.killerApp');
			        activeApp = null;
			    }
			    activeAppClick = false;
			});

        window.addEventListener('resize', setAppLocation);

        function setAppLocation() {
            var width = window.innerWidth;
            var container = $('.banner-tt');
            if (width > desktopWidth) {
                container.prependTo($('.killerapp-banner'));
            } else {
                // Only switch if container is still in desktop mode
                // otherwise the switch is done from mobile to mobile which is
                // unnecessary(and caused keyboard errors on android)
                if (container.parent('.killerapp-banner').length) {
                    container.prependTo($('.killerapp-banner-loose'));
                }
            }
        }	
        setAppLocation();

        return killerApps
			.each(function () {
			    var element = $(this),
					form = element.find('form'),
					$result = element.find('.result-container'),
					collapsed = true,
					originalHeight;

			    // undo the CSS height: 0;
			    form.css('height', 'auto');
			    // store the height
			    originalHeight = form.height();
			    // set the height back to 0
			    if (!element.closest('.killerapp-open-wrapper').length || element.hasClass('is-ratescalculator')) {
			        form.height(0);
			    } else {
			        // we don't need any handlers for opening/closing
			        return;
			    }

			    function toggleForm() {
			        originalHeight = form.css({
			        	height : 'auto',
			        	visibility : 'hidden'
			        }).height();
			        form
			        	.stop()
			        	.css({
				        	height : collapsed ? 0 : originalHeight,
				        	visibility : ''
				        })
			        	.animate({ height: collapsed ? originalHeight : 0 }, 200, function () {
				            element.removeClass('opening closing');
				        });
			    }

			    element
					.on('click touchend', function () {
					    activeAppClick = (activeApp && activeApp.is(element));
					})
					.on('toggle.killerApp', function () {
					    element.trigger(collapsed ? 'open.killerApp' : 'close.killerApp');
					})
					// Resize the fixed height form when a conditionally displayed element changes
					.on('updateSize.killerApp change.conditionalDisplay', function () {
					    var currentHeight = form.height();
					    originalHeight = form.css('height', 'auto').height();
					    form.height(currentHeight);
					    if (!collapsed) {
					        form.animate({ height: originalHeight }, 200);
					    }
					})
					.on('open.killerApp', function () {
					    if (collapsed) {
					        element.addClass('opening').removeClass('collapsed');
					        killerApps.not(element).trigger('close.killerApp');
					        toggleForm();
					        collapsed = false;
					        activeApp = element;
					        if (!element.hasClass('is-ratescalculator')) {
					            settings.onActivate();
					        }
					    }
					})
					.on('close.killerApp', function () {
					    if (!collapsed) {
					        if (!element.hasClass('is-ratescalculator')) {
					            element.addClass('collapsed closing');
					        } else {
					            element.addClass('closing');
					        }
					        toggleForm();
					        collapsed = true;
					        activeApp = null;
					        settings.onDeactivate();
					    }
					});


			    // form clicks always open:
			    form.on('click', function () {
			        if (collapsed) {
			            element.trigger('open.killerApp');
			        }
			    });
			    // header is a 'toggle':
			    element.find('header').on('click', function () {
			        element.trigger('toggle.killerApp');
			    });
			});
    };

    /**
	 * The rates calculator killer app
	 * Works on top of the base killerApp plugin
	 * @returns {jQuery}
	 */
    $.fn.ratesCalculator = function () {
        return $(this).each(function () {
            var app = $(this),
				dataUrl = app.data('data-source'),
				form = app.find('form'),
				json = null,
				renderTypes = {},
				conditions = {},
				variables = {},
				questionIndex = 0,
				isOpen = false,
				currentWeightsList;


            /**
			 * Saves the provided state variable with the given value
			 * @param {string} variable
			 * @param {*} value
			 * @returns {*} The given value
			 */
            function set(variable, value) {
                variables[variable] = value;
                return value;
            }

            /**
			 * Retrieves the variable from the state and returns it. Returns the defaultValue when it doesn't exist.
			 * @param {string} variable
			 * @param {*} [defaultValue]
			 * @returns {*}
			 */
            function get(variable, defaultValue) {
                if (variables.hasOwnProperty(variable)) {
                    return variables[variable];
                }
                return defaultValue;
            }

            /**
			 * Renders an array of questions
			 * @param {Array} questions The questions definition Array
			 * @param {Array} [values] Predefined set of question values
			 */
            function render(questions, values) {
                // lookup array for the next questions (siblings, not children):
                var nextQuestions = questions.slice();
                form.stop();

                $.each(questions, function (i, question) {
                    var type = question.type || '?',
						value = values ? $(values).filter(function (i, value) {
						    return value.name === question.id;
						}) : question.value,
						failed, row, tooltip, label;

                    if (value && value.length && typeof value.get === 'function') {
                        value = value.get(0).value;
                    }
                    // Remove this question from the upcoming questions list:
                    nextQuestions.shift();
                    question.nextQuestions = nextQuestions.slice();

                    if (renderTypes[type]) {
                        if (question.hasOwnProperty('conditions')) {
                            failed = $.grep(question.conditions, function (condition) {
                                if (conditions.hasOwnProperty(condition.type)) {
                                    return conditions[condition.type].apply(question, condition['arguments']);
                                }
                                return false;
                            }, true);

                            if (failed.length) {
                                // one or more conditions have failed, don't render:
                                return;
                            }
                        }

                        row = renderTypes[type](question, String(value));

                        if (row) {
                            row.addClass('form-row');
                            if (questionIndex === 0) {
                                row.addClass('first');
                            }
                            questionIndex++;

                            // a value has changed in this row:
                            row.on('questionChange.killerApp', function (event, data) {
                                var children = row.nextAll('.form-row');

                                if (data && data['export']) {
                                    $.each(data['export'], function (i, variable) {
                                        // when the export has no value, the value of the data is used:
                                        set(variable.key, variable.value !== undefined ? variable.value : data.value);
                                    });
                                }

                                // destroy any tooltips:
                                children.find('.tooltip').qtip('destroy', true);
                                // remove the elements:
                                children.remove();
                                // and update the index:
                                questionIndex = row.prevAll('.form-row').length + 1;
                            });

                            form.append(row);

                            // Initialize the tooltip:
                            if (question.info) {
                                tooltip = $('<div>', {
                                    'class': 'tooltip',
                                    'html': question.info
                                });
                                label = row.find('.label').first();

                                if (label.length) {
                                    if (label.hasClass('inline')) {
                                        label.after(tooltip);
                                    } else {
                                        label.append(tooltip);
                                    }
                                } else {
                                    // append the tooltip:
                                    row.append(tooltip);
                                }
                                window.initializeQTips(row);
                            }

                            row.trigger('questionRender.killerApp');
                        }
                    }
                });
                app.trigger('updateSize.killerApp');
            }

            /**
			 * Returns the currently selected regions based on the selected type and country
			 * @returns {Array}
			 */
            function getSelectedCountryRegions() {
                var listName = get('regionList'),
					countryId = get('country'),
					country;

                if (listName && countryId) {
                    country = $.grep(json.countries, function (country) {
                        return country.id === countryId;
                    })[0];
                    return country[listName];
                }

                return [];
            }

            /**
			 * Condition which tests if the currently selected weight has the given price key
			 * @param {string} priceKey
			 * @returns {bool}
			 */
            conditions.weightHasPriceKey = function (priceKey) {
                var currentWeightId = window.parseInt(get('currentWeight')),
					currentWeight;

                if (currentWeightId && currentWeightsList && currentWeightsList.hasOwnProperty('weights')) {
                    // fetch the currently selected weight:
                    currentWeight = $.grep(currentWeightsList.weights, function (weight) {
                        return window.parseInt(weight.value) === currentWeightId;
                    });

                    if (currentWeight.length) {
                        // return whether the selected weight has the price key:
                        return currentWeight[0].hasOwnProperty(priceKey);
                    }
                }
                return false;
            };

            /**
			 * Returns a radio input type
			 * @param {object} question
			 * @param {*} [value]
			 * @returns {jQuery}
			 */
            renderTypes.radio = function (question, value, typePackage) {
                //TODO check for flexible solution
                var container = $('<fieldset>', { 'class': 'radio' }),
					label = question.label ? $('<span>', {
					    'class': 'label',
					    'text': question.label,
					    'for': question.options[0].id || question.id + '-0'
					}) : 0,
					fields = $('<span>', { 'class': 'field' }),
					checkedField = null;

                // Force the value of checked (even when we don't have a value, to avoid remembering from a previous state)
                $.map(question.options, function (option) {
                    option.checked = String(option.value) === value;
                    return option;
                });

                // render the options
                $.each(question.options, function (i, option) {
                    var id = option.id || question.id + '-' + i,
						input = $('<input>', {
						    'class': 'input',
						    'type': 'radio',
						    'name': question.id,
						    'id': id,
						    'value': option.value,
						    'checked': option.checked
						});

                    if (option.checked) {
                        checkedField = input;
                    }

                    input.on('change', function () {
                        var children = option.children || question.children || question.nextQuestions;
                        // trigger a change (to remove all next rows)
                        container.trigger('questionChange.killerApp', option);
                        // render my children:
                        if (children) {
                            render(children);
                        }
                    });

                    if (typePackage) {
                        fields.append($('<span>', {
                            'class': 'field-half'
                        }).append(input).append(
							$('<label>', {
							    'class': ('inline label package package-' + i),
							    'for': id,
							    'text': option.label || '?'
							})).on('click', function () {
							    input.prop('checked', true).trigger('change');
							})
						);
                    } else {
                        fields.append(input).append(
							$('<label>', {
							    'class': 'inline label',
							    'for': id,
							    'text': option.label || '?'
							}).on('click', function () {
							    input.prop('checked', true).trigger('change');
							})
						);
                    }
                });

                if (label) {
                    container.append(label)
                }
                container.append(fields);

                if (checkedField) {
                    window.setTimeout(function () {
                        checkedField.trigger('change');
                    }, 50);
                }

                return container;
            };

            /**
			 * Returns an illustrated radio input type
			 * @param {object} question
			 * @param {*} [value]
			 * @returns {jQuery}
			 */
            renderTypes.package = function (question, value) {
                return renderTypes.radio(question, value, true);
            };

            /**
			 * Returns a select input type
			 * @param {object} question
			 * @param {*} [value]
			 * @returns {jQuery}
			 */
            renderTypes.select = function (question, value) {
                var container = $('<div>', { 'class': 'select' }),
					label = $('<label>', {
					    'class': 'label',
					    'text': question.label,
					    'for': question.id
					}),
					fields = $('<span>', { 'class': 'field' }),
					select = $('<select>', {
					    'class': 'inputselect',
					    'name': question.id,
					    'id': question.id
					}),
					hasSelectedOptions = false;

                if (question.placeholder) {
                    if (question.type != 'country') {
                        select.append($('<option>', {
                            'value': '',
                            'text': question.placeholder
                        }));
                    }
                }

                select.append($.map(question.options, function (option) {
                    return $('<option>', {
                        'value': option.value,
                        'text': option.label,
                        'class': option.class,
                        'disabled': option.disabled,
                        'selected': (function () {
                            if (option.select == "asc") {
                                hasSelectedOptions = true;
                                return true;
                            }
                            return false;
                        }())
                    });
                })).appendTo(fields);

                select.on('change', function () {
                    var currentValue = select.val(),
						option = $(question.options).filter(function () {
						    return this.value === currentValue;
						}).get(0),
						children = option && option.children ? option.children : question.children || question.nextQuestions;

                    // trigger a change which (re)renders all children
                    question.value = currentValue;
                    container.trigger('questionChange.killerApp', question);
                    // render my children:
                    if (children) {
                        render(children);
                    }
                });

                // When a <select> is rendered with a value, immediately trigger a change when rendered:
                if (hasSelectedOptions) {
                    container.on('questionRender.killerApp', function () {
                        container.find('.input, .inputselect').trigger('change');
                    });
                }

                return container.append(label, fields);
            };

            /**
			 * Returns a (single) checkbox input
			 * @param {object} question
			 * @param {*} [value]
			 * @returns {jQuery}
			 */
            renderTypes.checkbox = function (question, value) {
                var container = $('<div>', { 'class': 'checkbox' }),
					label = $('<label>', {
					    'class': 'inline label',
					    'text': question.label,
					    'for': question.id
					}),
					input = $('<input>', {
					    'class': 'input',
					    'type': 'checkbox',
					    'name': question.id,
					    'id': question.id,
					    'value': value || question.value,
					    'checked': question.checked
					});

                input.on('change', function () {
                    var checked = input.prop('checked'),
					// find the option that matches our checked state:
						option = $(question.options).filter(function () {
						    return (this.checked === 'true' || this.checked === true) === checked;
						}).get(0),
						children = option && option.children ? option.children : question.children || question.nextQuestions;

                    container.trigger('questionChange.killerApp', option);
                    // render the children of the option
                    if (children) {
                        render(children);
                    }
                });

                return container.append(input, label);
            };

            /**
			 * Outputs the HTML in the text property of the question.
			 * @param {object} question
			 * @returns {jQuery}
			 */
            renderTypes.html = function (question) {
                return $('<div>', {
                    'class': 'html',
                    'html': question.text
                });
            };

            /**
			 * Returns a 'select' renderType with countries and populates the 'country' variable.
			 * @param {object} question
			 * @param {*} [value]
			 * @returns {jQuery}
			 */
            renderTypes.country = function (question, value) {

                json.countries.sort(predicate(
                    'selected', 'frequent', 'name'));

                var first = false;
                question.options = $.map(json.countries, function (country) {
                    if (country.id == "separator") {
                        return {
                            'value': "",
                            'label': "",
                            'disabled': true,
                            'class': 'separator'
                        } 
                    } else {
                        return {
                            'label': country.name,
                            'value': country.id,
                            'disabled': false,
                            'select': country.selected
                        };
                    }
                });
                return renderTypes.select(question, value);
            };

            function predicate() {
                var fields = [],
                  n_fields = arguments.length,
                  field, name, reverse, cmp;

                var default_cmp = function (a, b) {
                    if (a === b) return 0;
                    return a < b ? -1 : 1;
                },
                  getCmpFunc = function (primer, reverse) {
                      var dfc = default_cmp,
                        // closer in scope
                        cmp = default_cmp;
                      if (primer) {
                          cmp = function (a, b) {
                              return dfc(primer(a), primer(b));
                          };
                      }
                      if (reverse) {
                          return function (a, b) {
                              return -1 * cmp(a, b);
                          };
                      }
                      return cmp;
                  };

                // preprocess sorting options
                for (var i = 0; i < n_fields; i++) {
                    field = arguments[i];
                    if (typeof field === 'string') {
                        name = field;
                        cmp = default_cmp;
                    } else {
                        name = field.name;
                        cmp = getCmpFunc(field.primer, field.reverse);
                    }
                    fields.push({
                        name: name,
                        cmp: cmp
                    });
                }

                // final comparison function
                return function (A, B) {
                    var a, b, name, result;
                    for (var i = 0; i < n_fields; i++) {
                        result = 0;
                        field = fields[i];
                        name = field.name;

                        result = field.cmp(A[name], B[name]);
                        if (result !== 0) break;
                    }
                    return result;
                };
            }

            /**
			 * Weight select, retrieves the correct list and returns a 'select' renderType.
			 * @param {object} question
			 * @param {*} [value]
			 * @returns {jQuery|bool}
			 */
            renderTypes.weight = function (question, value) {
                var listName = get('regionList'),
					countryRegions = getSelectedCountryRegions(),
					weightList, rates;

                if (countryRegions.length) {
                    weightList = json[listName];

                    // find the first correct entry in the weight list based on the regions of the country:
                    rates = $.grep(weightList, function (weight) {
                        return $.inArray(weight.id, countryRegions) !== -1;
                    })[0];

                    // make the current rates available to other questions
                    currentWeightsList = rates;

                    if (rates) {
                        // reformat the weights to an option array
                        question.options = $.map(rates.weights, function (option) {
                            return {
                                'label': option.label,
                                'value': option.value
                            };
                        });

                        return renderTypes.select(question, value);
                    }

                    return false;
                }
                window.alert('No region list set! Unable to determine what type of mail is sent (post/package).');
                return false;
            };

            /**
			 * Region based HTML output, chooses the correct text based on the country and returns a 'html' renderType.
			 * @param {object} question
			 * @returns {jQuery}
			 * @see renderTypes.html()
			 */
            renderTypes.regionExitHtml = function (question) {
                var regions = getSelectedCountryRegions(),
					textKey = 'default',
					key;

                for (key in question.texts) {
                    if (question.texts.hasOwnProperty(key) && $.inArray(key, regions) !== -1) {
                        textKey = key;
                    }
                }

                question.text = $('<div>').html(question.texts[textKey] || '').text();
                return renderTypes.html(question);
            };


            //START NEW KILLER-APP
            renderTypes.resultsButton = function (question) {
                var $element = $('<div>', {
                    'class': 'html submit-buttons'
                }).append($('<p>').append($('<button>', {
                    'class': 'button',
                    'html': question.label
                })));

                // observeer de button op clicks
                $element.on('click', function (event) {

                    event.preventDefault();
                    renderChannels();
                    showPromos();
                });
                // na click doe je ding, verbergen enzo, tonenn uitgangen.
                return $element;
            };

            function returnToForm() {
                $('.rates-calculator').removeClass('result').find('.result-row.price-display').each(function () {
                    $(this).remove();
                });
                $('.rates-calculator').find('.result-row.promo').each(function () {
                    $(this).remove();
                });
            }

            //show nieuwe 'uitgangen'
            function renderChannels() {
                var regionList = get('regionList'),
					countryRegions = getSelectedCountryRegions(),
					weightList = json[regionList],
					currentWeightId = parseInt(get('currentWeight')),
					weights,
					priceList,
					priceKey = get('priceKey'),
					isRegistered = priceKey === 'registered',
					currentWeight,
                    weightResults,
					channelsList,
                    parameterList,
					currencySign = json.currency[0].currencySign;
                weights = $.grep(weightList, function (weight) {
                    return $.inArray(weight.id, countryRegions) !== -1;
                });

                priceList = $.grep(currentWeightsList.weights, function (weight) {
                    return window.parseInt(weight.value) === currentWeight;
                })[0];
 
                var results = [];
                for (var i = 0; i < weights.length; i++) {
                    var tempWeights = weights[i];
                    for (var z = 0; z < tempWeights.weights.length; z++) {
                        if (tempWeights.weights[z].value == currentWeightId) {
                            results.push(tempWeights.weights[z]);
                        }
                    }
                }

                var channelsLists = [];
                for (var i = 0; i < results.length; i++) {
                    channelsList = $.grep(results[i].channels, function (list) {
                        var registeredList = [];
                        if ((typeof list.registered) == "object") {
                            for (var registeredType in list.registered) {
                                if (list.registered[registeredType] == "true") {
                                    registeredList.push(true);
                                } else if (list.registered[registeredType] == "false") {
                                    registeredList.push(false);
                                }
                            }
                        } else {
                            if (list.registered == "true") {
                                registeredList.push(true);
                            } else if (list.registered == "false") {
                                registeredList.push(false);
                            }
                        }
                        return $.inArray(isRegistered, registeredList) !== -1;
                    });
                    channelsLists = $.merge(channelsLists, channelsList);
                }

                var embeddedChannelList = [];
                for (var i = 0; i < channelsLists.length; i++) {
                    if (channelsLists[i].root) {
                        for (var channel = 0; channel < channelsLists[i].root.channels.length; channel++) {
                            embeddedChannelList.push(channelsLists[i].root.channels[channel]);
                        }
                    }
                }

                function getRegions(country, type)
                {
                    for (var c in json.countries) {
                        if (json.countries[c].name == country) {
                            if (type == 'post') {
                                return json.countries[c]['post-regions'];
                            } else {
                                return json.countries[c]['package-regions'];
                            }
                        }
                    }
                }

                channelsList = embeddedChannelList;

                if (channelsList.length) {
                    //channelsList = channelsList[0].root.channels;
                    $('.rates-calculator').addClass('result');

                    var types = ['Brief', 'Pakket', 'Postzegel'];
                    var typeValues = ['Letters', 'Parcels', 'LetterStampCode'];
                    var paramKeys = ['catalogue', 'productCode', 'weightClass', 'countryIsoCode'];
                    var formType = $('input[name=post-package]:checked').val();
                    var weight, country, countryVal, registered, regions;
                    if (formType == 1) {
                        weight = $('#package-weight option:selected').text();
                        country = $('#package-country').val();
                        countryVal = $('#package-country option:selected').text();
                        registered = $('#package-registered').is(':checked');
                        regions = getRegions(countryVal, 'package');
                    } else {
                        weight = $('#post-weight option:selected').text();
                        countryVal = $('#post-country option:selected').text();
                        country = $('#post-country').val();
                        registered = $('#post-registered').is(':checked');
                        regions = getRegions(countryVal, 'post');
                    }

                    var tmpRegions = [];
                    for (var i = 0; i < regions.length; i++) {
                        tmpRegions.push(regions[i].toLowerCase());
                    }
                    regions = tmpRegions;

                    $.each(channelsList, function (i, channel) {
                        var param = (channel.href.indexOf('?params') > -1) ? true : false;
                        var stamp = (channel.href.indexOf('?stamp') > -1) ? true : false;
                        if ((param || stamp) && json.parameterValues.parameter != null) {
                            var typeValue = typeValues[formType];
                            var tridionType = types[formType];
                            var replacement = "?params"
                            if (stamp) {
                                typeValue = typeValues[2];
                                tridionType = types[2];
                                replacement = "?stamp"
                            }
                            parameterList = json.parameterValues.parameter;
                            for (i = 0; i < parameterList.length; i++) {
                                if (parameterList[i].type == tridionType && parameterList[i].weight_key == weight && (parameterList[i].region == "" || regions.indexOf(parameterList[i].region.toLowerCase()) > -1) && (parameterList[i].tab == "" || parameterList[i].tab == channel.tab)) {
                                    var product_code = parameterList[i].product_code;
                                    var weight_class = parameterList[i].weight;
                                    if (registered && parameterList[i].product_code_registered != '') {
                                        product_code = parameterList[i].product_code_registered;
                                    }
                                    if (registered && parameterList[i].weight_registered != '') {
                                        weight_class = parameterList[i].weight_registered;
                                    }
                                    var url = '?catalogue=' + typeValue
                                            + '&productCode=' + product_code
                                            + '&weightClass=' + weight_class
                                            + '&countryIsoCode=' + country;
                                    channel.href = channel.href.replace(replacement, url);
                                }
                            }
                        }

                        // bouw exit html
                        var $channel = $('<div>', {
                            'class': 'result-row price-display'
                        }).append($('<a>', {
                            'class': 'wrapper',
                            'href': channel.href
                        }).append($('<h4>', {
                            'html': channel.title
                        })).append($('<span>', {
                            'class': 'price',
                            'html': currencySign + channel[priceKey]
                        })).append($('<p>', {
                            'html': channel.info
                        })));
                        if (channel.promoted == "true") {
                            $channel.addClass('promoted');
                        }
                        if (channel.popup == "true") {
                            $channel.find("a").attr('target', '_blank');
                        }
                        if (channel[priceKey] != '-') {
                            $('.rates-calculator').find('.result-container').append($channel);
                        }

                    });
                }
                //backbutton
                $('#js-killer-app-previous').on('click', function () {
                    returnToForm();
                });
            }

            //show 'vaste elementen'
            function showPromos() {

                var regionList = get('regionList'),
					countryRegions = getSelectedCountryRegions(),
					weightList = json[regionList],
					weights,
					promosList;
                weights = $.grep(weightList, function (weight) {
                    return $.inArray(weight.id, countryRegions) !== -1;
                })[0];

                promosList = weights.rootPromos.promos;
                // bouw exit html
                var $promo = $('.rates-calculator').find('.result-container').append($('<div>', {
                    'class': 'result-row promo'
                }));

                $.each(promosList, function (i, promo) {
                    // bouw exit html
                    var $block = $('<div>');

                    if (promo.title) {
                        $block.append($('<h4>', {
                            'html': promo.title
                        })).addClass('extra');
                    }

                    $block.append($('<p>').append($('<a>', {
                        'href': promo.href,
                        'html': promo.text
                    })));
                    if (promo.popup == "true") {
                        $block.find("a").attr('target', '_blank');
                    }
                    $promo.find('.promo').append($block);
                });
            }

            //END NEW KILLER-APP

            /**
			 * Handles the 'open' event, loads the JSON and renders the initial questions
			 */
            app.on('open.killerApp', function () {
                var values = form.serializeArray();

                form.empty();
                form.trigger('reset');
                questionIndex = 0;
                if (json === null) {
                    app.addClass('loading');
                    $.ajax({
                        dataType: 'json',
                        url: dataUrl,
                        success: function (data) {
                            if (data.questions !== undefined) {
                                json = data;
                                app.removeClass('loading');
                                render(json.questions, values);
                            }
                        },
                        error: function () {
                            app.removeClass('loading');
                            render([
								{
								    'type': 'html',
								    'text': i18n.get('killer-apps.load-error')
								}
                            ], values);
                        }
                    });
                } else {
                    if (json.questions !== undefined) {
                        render(json.questions, values);
                    }
                }
                isOpen = true;
            });

            /**
			 * Handles the 'close' event, cleans the generated questions.
			 */
            app.on('close.killerApp', function () {
                if (isOpen) {
                    // Fixes a bug which causes inputs to retain their value...
                    form.find('input[type=radio]').prop('checked', false).empty();
                    form.empty();
                    questionIndex = 0;
                    render(json.questions);
                    isOpen = false;
                    app.trigger('updateSize.killerApp');
                    returnToForm();
                }
            });

            /**
			 * When the app is created the first question is rendered but since we want to render each question
			 * dynamically we need to copy the value of the first question.
			 */
            form.on('click', '.form-row:first-child label', function () {
                var label = $(this),
					placeholderInput = $('#' + label.attr('for')),
					placeholderInputType = placeholderInput.attr('type').toLowerCase();

                if ($.inArray(placeholderInputType, ['radio', 'checkbox']) >= 0) {
                    placeholderInput.prop('checked', true);
                }
            });

            /**
			 * When the form is submitted using a button with an 'action' data attribute
			 * the form action is updated and the form is submitted.
			 * Example button: <button type="submit" data-action="http://www.google.com/">Submit form to Google</button>
			 */
            form.on('click', 'button[data-action]', function () {
                form.attr('action', $(this).data('action'));
            });
        });
    };

    // immediately invoke the rates calculator killer app:
    $('.rates-calculator.killer-app-old').ratesCalculator();

    $('div.killer-apps-old article.column').each(function (key, value) {
        $(this).click(function () {
            // Get form in killerapp.
            var form = $(this).find('form');

            // Default focus is false
            var isFocus = false;

            // Get killerapp height
            var height = Number(form.css('height').replace('px', ''));

            // If form height is bigger then 80.
            if (height > 80) {
                isFocus = true;
            }

            if (isFocus == false) {
                // Focus at the first empty input text field. 
                checkInputText(form);

                // Select first
                var checked = isChecked(form);
                if (!checked) {
                    checkFirstRadio(form);
                }
            }
        });
    });

    var focusZipcodesearch = function () {
        if ($('section.tab-content').length) {
            var form = $('section.tab-content').find('form');
            checkInputText(form);
        }
    };

    // Set focus to first empty input field.
    var checkInputText = function (form) {
        var ret = "";
        form.find('input[type=text]').each(function (key, value) {
            if ($(this).val() == "" && ret == "") {
                ret = this;
            }
        });
        if (ret == "") {
            ret = form.find('input[type=text]').last();
        }
        $(ret).focus();
    };

    // If radio button is checked.
    var isChecked = function (form) {
        var ret = false;
        form.find('input[type=radio]').each(function (key, value) {
            var checked = $(this).is(':checked');
            if (checked) {
                ret = true;
            }
        });
        return ret;
    };

    // Check first radio button.
    var checkFirstRadio = function (form) {
        var excludeIds = ['post-package-0'];
        var radio = form.find('input[type=radio]').first();

        var used = $.inArray(radio.attr('id'), excludeIds) > -1;
        if (used) {
            radio.prop('checked', true);
        }
    };

    focusZipcodesearch();
});

/*jslint browser: true, plusplus: true, regexp: true, indent: 4, white:true */
/*global jQuery, Modernizr */
/**
 * This purpose of this file is to implement a accordion
 *
 * This functionality is provided via a jQuery plugin.
 *
 * Example - basic accordion
 *
 * html:
 * 	<div class="accordion">
 * 		<h3 class="accordion-header" data-panel-ref="1">Title 1</h3>
 * 		<div class="accordion-panel" data-panel-id="1">
 * 			Hello world 1
 * 		</div>
 * 		<h3 class="accordion-header" data-panel-ref="2">Title 2</h3>
 * 		<div class="accordion-panel" data-panel-id="2">
 * 			Hello world 2
 * 		</div>
 * 		<h3 class="accordion-header" data-panel-ref="3">Title 3</h3>
 * 		<div class="accordion-panel" data-panel-id="3">
 * 			Hello world 3
 * 		</div>
 * 	</div>
 *
 * javascript:
 * 	$('.selector').accordion();
 *
 */
(function ($) {
	'use strict';

	var defaultOptions = {
		panelButtonSelector: '',
		panelContentSelector: '',

		/**
		 * Data attribute of panel button
		 * @param {String} panelButtonDataAttribute
		 */
		panelButtonDataAttribute: 'data-panel-ref',

		/**
		 * Data attribute of panel content
		 * @param {String} panelContentDataAttribute
		 */
		panelContentDataAttribute: 'data-panel-id',

		/**
		 * Css selector of active element
		 * @param {String} activeClassname
		 */
		activeClassname: 'active',

		/**
		 * Name of the function to execute
		 * @param {String} togglePanel
		 */
		panelButtonAction : 'togglePanel'
	};

	var Accordion = function( options ){
		var openPanelId;
		$.extend(this, defaultOptions, options);

		this.bindElements();

		if ( this.openPanelId ){
			openPanelId = this.openPanelId;
			this.openPanelId = null;
			this.openPanel( openPanelId );
		}
	};

	$.extend( Accordion.prototype, {
		bindElements : function(){
			var $accordionElement = this.$element;

			this.$panelContentElements = $accordionElement.find(this.panelContentSelector + '[' + this.panelContentDataAttribute + ']');
			this.$panelButtonsElements = $accordionElement.find(this.panelButtonSelector + '[' + this.panelButtonDataAttribute + ']');

			this.$panelButtonsElements.on('click touchend', $.proxy(function(e){
				var $buttonElement = $(e.delegateTarget),
					panelId = $buttonElement.attr(this.panelButtonDataAttribute);

				this[ this.panelButtonAction ](panelId);

				if (e.target.tagName === 'a' || e.type === 'touchend'){
					e.preventDefault();
				}
			}, this));
		},

		/**
		 * Open the corresponding panel and then remove the active classes from the $panelContentElements
		 * and $panelContentElements using a filter function to make use of the already matched elements in
		 * the DOM. The :not selector is used to select everything except the current panelId.
		 *
		 * After removal of the active classes, the active class is added to the current $panelContentElements
		 * and $panelButtonsElements using the toggleClass function that determines if the class should be
		 * added or removed depending on the class presence
		 */
		togglePanel : function( panelId ){
			var $panelContentElements = this.$panelContentElements,
				$panelButtonsElements = this.$panelButtonsElements;

			this.closePanels( panelId );

			$panelButtonsElements.filter('[' + this.panelButtonDataAttribute + '="'+ panelId +'"]').toggleClass(this.activeClassname);
			$panelContentElements.filter('[' + this.panelContentDataAttribute + '="'+ panelId +'"]').toggleClass(this.activeClassname);

			this.checkOpenPanelChange();
		},

		openPanel : function( panelId ){
			var $panelContentElements = this.$panelContentElements,
				$panelButtonsElements = this.$panelButtonsElements;

			this.closePanels( panelId );

			$panelButtonsElements
				// mark button as active
				.filter('[' + this.panelButtonDataAttribute + '="'+ panelId +'"]')
				.addClass(this.activeClassname)

				// make sure that radio buttons inside panel button selector are checked
				.find('input[type="radio"]').prop('checked', true);

			// show content bound to panel button
			$panelContentElements.filter('[' + this.panelContentDataAttribute + '="'+ panelId +'"]').addClass(this.activeClassname);

			this.checkOpenPanelChange();
		},

		closePanels : function( excludedPanelId ){
			var $panelContentElements = this.$panelContentElements,
				$panelButtonsElements = this.$panelButtonsElements;

			if ( excludedPanelId != undefined ){
				$panelButtonsElements = $panelButtonsElements.filter(':not([' + this.panelButtonDataAttribute + '="'+ excludedPanelId +'"])');
				$panelContentElements = $panelContentElements.filter(':not([' + this.panelContentDataAttribute + '="'+ excludedPanelId +'"])');

			}

			$panelButtonsElements.removeClass(this.activeClassname);
			$panelContentElements.removeClass(this.activeClassname);
		},

		checkOpenPanelChange : function(){
			var openPanel = this.$panelContentElements.filter('.' + this.activeClassname),
				openPanelId = openPanel.attr(this.panelContentDataAttribute);

			if ( this.openPanelId != openPanelId ){
				this.openPanelId = openPanelId;
				this.$element.trigger('openpanelchange', [openPanelId]);
			}

			if ( this.openPanelId ){
				this.$element.addClass(this.activeClassname);
			} else {
				this.$element.removeClass(this.activeClassname);
			}
		}
	} );

	$.fn.extend({
		accordion: function(options){
			options = $.extend({}, options || {});

			return this.each(function(){
				var $element = $(this),
					accordionInstance = $element.data('accordionInstance');

				if ( !accordionInstance ){
					options.$element = $element;
					accordionInstance = new Accordion(options);
					$element.data('accordionInstance', accordionInstance);
				} else {
					$.each( options, function( option, value ){
						switch(option){
							case 'openPanelId':
								accordionInstance.openPanel( value )
								break;

							case 'togglePanel':
								accordionInstance.togglePanel( value )
								break;
						}
					} );
				}
			});
		}
	})
})(jQuery);

/**
 * Debounce method borrowed from Lodash
 * ====================================
 * Creates a function that delays invoking `func` until after `wait` milliseconds
 * have elapsed since the last time it was invoked. The created function comes
 * with a `cancel` method to cancel delayed invocations. Provide an options
 * object to indicate that `func` should be invoked on the leading and/or
 * trailing edge of the `wait` timeout. Subsequent calls to the debounced
 * function return the result of the last `func` invocation.
 *
 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
 * on the trailing edge of the timeout only if the the debounced function is
 * invoked more than once during the `wait` timeout.
 *
 * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
 * for details over the differences between `_.debounce` and `_.throttle`.
 *
 * @static
 * @memberOf _
 * @category Function
 * @param {Function} func The function to debounce.
 * @param {number} [wait=0] The number of milliseconds to delay.
 * @param {Object} [options] The options object.
 * @param {boolean} [options.leading=false] Specify invoking on the leading
 *  edge of the timeout.
 * @param {number} [options.maxWait] The maximum time `func` is allowed to be
 *  delayed before it is invoked.
 * @param {boolean} [options.trailing=true] Specify invoking on the trailing
 *  edge of the timeout.
 * @returns {Function} Returns the new debounced function.
 * @example
 *
 * // avoid costly calculations while the window size is in flux
 * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
 *
 * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
 * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
     *   'leading': true,
     *   'trailing': false
     * }));
 *
 * // ensure `batchLog` is invoked once after 1 second of debounced calls
 * var source = new EventSource('/stream');
 * jQuery(source).on('message', _.debounce(batchLog, 250, {
     *   'maxWait': 1000
     * }));
 *
 * // cancel a debounced call
 * var todoChanges = _.debounce(batchLog, 1000);
 * Object.observe(models.todo, todoChanges);
 *
 * Object.observe(models, function(changes) {
     *   if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
     *     todoChanges.cancel();
     *   }
     * }, ['delete']);
 *
 * // ...at some point `models.todo` is changed
 * models.todo.completed = true;
 *
 * // ...before 1 second has passed `models.todo` is deleted
 * // which cancels the debounced `todoChanges` call
 * delete models.todo;
 */



function debounce(func, wait, options) {
	'use strict';

	var args,
		maxTimeoutId,
		result,
		stamp,
		thisArg,
		timeoutId,
		trailingCall,
		lastCalled = 0,
		maxWait = false,
		trailing = true,
		leading,
		now = Date.now || function () {
			return new Date().getTime();
		};

	wait = wait < 0 ? 0 : (+wait || 0);
	if (options === true) {
		leading = true;
		trailing = false;
	} else if (jQuery.isPlainObject(options)) {
		leading = options.leading;
		maxWait = options.hasOwnProperty('maxWait') && Math.max(+options.maxWait || 0, wait);
		trailing = options.hasOwnProperty('trailing') ? options.trailing : trailing;
	}

	function cancel() {
		if (timeoutId) {
			clearTimeout(timeoutId);
		}
		if (maxTimeoutId) {
			clearTimeout(maxTimeoutId);
		}
		maxTimeoutId = timeoutId = trailingCall = undefined;
	}

	function delayed() {
		var remaining = wait - (now() - stamp),
			isCalled;
		if (remaining <= 0 || remaining > wait) {
			if (maxTimeoutId) {
				clearTimeout(maxTimeoutId);
			}
			isCalled = trailingCall;
			maxTimeoutId = timeoutId = trailingCall = undefined;
			if (isCalled) {
				lastCalled = now();
				result = func.apply(thisArg, args);
				if (!timeoutId && !maxTimeoutId) {
					args = thisArg = null;
				}
			}
		} else {
			timeoutId = setTimeout(delayed, remaining);
		}
	}

	function maxDelayed() {
		if (timeoutId) {
			clearTimeout(timeoutId);
		}
		maxTimeoutId = timeoutId = trailingCall = undefined;
		if (trailing || (maxWait !== wait)) {
			lastCalled = now();
			result = func.apply(thisArg, args);
			if (!timeoutId && !maxTimeoutId) {
				args = thisArg = null;
			}
		}
	}

	function debounced() {
		var leadingCall, remaining, isCalled;

		args = arguments;
		stamp = now();
		thisArg = this;
		trailingCall = trailing && (timeoutId || !leading);

		if (maxWait === false) {
			leadingCall = leading && !timeoutId;
		} else {
			if (!maxTimeoutId && !leading) {
				lastCalled = stamp;
			}
			remaining = maxWait - (stamp - lastCalled);
			isCalled = remaining <= 0 || remaining > maxWait;

			if (isCalled) {
				if (maxTimeoutId) {
					maxTimeoutId = clearTimeout(maxTimeoutId);
				}
				lastCalled = stamp;
				result = func.apply(thisArg, args);
			}
			else if (!maxTimeoutId) {
				maxTimeoutId = setTimeout(maxDelayed, remaining);
			}
		}
		if (isCalled && timeoutId) {
			timeoutId = clearTimeout(timeoutId);
		}
		else if (!timeoutId && wait !== maxWait) {
			timeoutId = setTimeout(delayed, wait);
		}
		if (leadingCall) {
			isCalled = true;
			result = func.apply(thisArg, args);
		}
		if (isCalled && !timeoutId && !maxTimeoutId) {
			args = thisArg = null;
		}
		return result;
	}
	debounced.cancel = cancel;
	return debounced;
}

/**
 * Window resize handler binding with a check for IE8 (which triggers resize on changes in the HTML).
 */
(function ($) {

	if ($.fn.accordion) {
		$('.accordion')
			.accordion({ 'openPanelId': 1 })
			.find('.accordion-header')
			.on('click', function () {
				var
					header = $(this);
				if (header.is('.active') && window.animatedScrollTo) {
					window.animatedScrollTo(header.offset().top - 70);
				}
			});
	}

	var $window = $(window),
		resizeHandlers = [],
		oldIE = document.all && !document.getElementsByClassName,
		observing = false,
		currentWidth, currentHeight;


    /**
     * Prevent default and open link in 'popup' window
     */
	function setExternalPopup() {
		$('.popup-extern').each(function () {
			var externalPopup = $(this);
			externalPopup
				.find('a')
				.off('click.externalPopup')
				.on('click.externalPopup', function (event) {
					event.preventDefault();
					if (!externalPopup.is('disabled') && !externalPopup.hasClass('unavailable')) {
						window
							.open(
								this.href,
								'chat',
								'status=no,location=no,toolbar=no,width=800,height=500,resizable=yes')
							.trigger('focus');
					}
				});
		});
	}
	window.setExternalPopup = setExternalPopup;
	setExternalPopup();

	function handleControlledResize() {
		var newWidth = $window.width(),
			newHeight = $window.height(),
			args = arguments;

		if (newWidth !== currentWidth || newHeight !== currentHeight) {
			currentWidth = newWidth;
			currentHeight = newHeight;
			$.each(resizeHandlers, function (i, handler) {
				return handler.apply(window, args);
			});
		}
	}

	function addResizeHandler(handler) {
		if (oldIE) {
			resizeHandlers.push(handler);
			if (!observing) {
				$(window).on('resize', debounce(handleControlledResize, 100, { 'maxWait': 500 }));
			}
		} else {
			$window.on('resize', debounce(handler, 100, { 'maxWait': 500 }));
		}
	}

	window.addResizeHandler = addResizeHandler;
}(jQuery));

var matchedMedia = (function () {
	var retina = '(-webkit-min-device-pixel-ratio: 2), '
		+ '(-moz-min-device-pixel-ratio: 2), '
		+ '(min-resolution: 2dppx), '
		+ '(min-resolution: 192dpi)',
		media = {
			'mobile-portrait': 'screen and (min-width: 320px)',
			'mobile-landscape': 'screen and (min-width: 480px)',
			'tablet-portrait': 'screen and (min-width: 661px)', // 768px
			'tablet-landscape': 'screen and (min-width: 1000px)', // 1024px
			'desktop': 'screen and (min-width: 1151px)'
		},
		matchedMedia = {
			'retina': window.matchMedia(retina).matches
		},
		retinaPostFix = '-x2',
		defaultMedia = jQuery.extend({}, media),
		keys, key;

	if (matchedMedia.retina) {
		for (key in defaultMedia) {
			if (defaultMedia.hasOwnProperty(key)) {
				media[key + retinaPostFix] = media[key];
			}
		}
	}

    /**
     * Updates the matched media to the current state
     */
	function updateMatchedMedia() {
		var medium;
		keys = [];
		for (medium in media) {
			if (media.hasOwnProperty(medium)) {
				if (matchedMedia[medium] = window.matchMedia(media[medium]).matches) {
					keys.push(medium);
				}
			}
		}
	}

	updateMatchedMedia();

	// Create a resize handler
	addResizeHandler(updateMatchedMedia);

	return function () {
		return {
			'keys': keys,
			'media': matchedMedia,
			'matches': function (medium) {
				return keys.indexOf(medium) >= 0;
			}
		};
	};
}());

/**
 * jQuery plug-ins
 */
(function ($) {
	'use strict';

	$.fn.renderHandleBars = function (context) {
		return this.each(function () {
			var
				self = $(this),
				data = self.data('handleBarsData'),
				template = data && data.template ? data.template : Handlebars.compile(
					self
						.find('script')
						.html()
				);
			context = $.extend(
				true,
				data && data.context ? data.context : self.data(),
				context || {}
			);
			self
				.html(
					template(
						context
					)
				)
				.data('handleBarsData', {
					template: template,
					context: context
				});
		});
	}

	/**
	 * Adds responsive behavior to images
	 * @returns {jQuery}
	 */
	$.fn.responsiveImage = $.fn.responsiveImage || function () {
		var images = $(this);

		/**
		 * Updates the image sources
		 */
		function updateSources() {
			var image = $(this),
				originalSrc = image.data('original-src'),
				currentSrc = image.attr('src'),
				breakpoint = matchedMedia(),
				allowHide = false,
				newSrc,
				src,
				i;

			if (!originalSrc) {
				originalSrc = currentSrc;
				image.data('original-src', currentSrc);
				allowHide = true;
			}

			// walk backwards from largest medium to smallest
			for (i = breakpoint.keys.length - 1; i >= 0; i--) {
				src = image.data('src-' + breakpoint.keys[i]);
				if (breakpoint.media[breakpoint.keys[i]] && src) {
					newSrc = src;
					break;
				}
			}

			if (allowHide) {
				if (newSrc && newSrc !== currentSrc) {
					// show the image hidden in the stylesheet
					image
						.one('load', function () {
							setTimeout(function () {
								image.addClass('visible');
							}, 10);
						});
				} else {
					image.addClass('visible');
				}
			}

			// set the new src
			if (newSrc) {
				if (newSrc !== currentSrc) {
					image.attr('src', newSrc);
				}
			} else if (currentSrc !== originalSrc) {
				// revert back to the original source
				image.attr('src', originalSrc);
			}
		}

		// Create a resize handler
		addResizeHandler(function () {
			images.each(updateSources);
		});

		return images.each(updateSources);
	};

	var pnlUserMenu = $('pnl-user-menu');

	pnlUserMenu
		.on('onLoginRequested onLogoutRequested', function(event) {
			var cookie = new Cookie('login-redirect', document.location.href).setDays(.02); // approx 30 minutes
			cookie.path = '/';
			cookie.write();
		})
		.on('onAuthenticationChange', function (event) {
			if (event.detail) {
				window.userDetails = event.detail;
				$(window).trigger('userDetails', window.userDetails);
			}
		});

	/* cookie notice */
	(function (container) {
		if (!container.length) {
			// old implementation
			/* cookie policy bar h#$%ckery */
			var $container = $('#cookiebar-container');
			$container.find("link[rel='stylesheet']").remove();

			// returns true, false or null if not (properly) set;
			window.hasCookiePermission = function () {

				// for testing purposes without loaded cookie script
				if (typeof TOL_showToestemming !== 'function') {
					return true;
				}
				if (JSON === undefined || typeof JSON.parse !== 'function') {
					return null;
				}
				try {
					var Allow = JSON.parse(getCookie()).Allow;
					return Allow === false || Allow === true ? Allow : null;
				}
				catch (err) {
					return null;
				}
			};

			if (window.hasCookiePermission() === null) {
				if (window.location.pathname === "/privacy-verklaring/" || window.location.pathname === "/cookie-verklaring/" || window.location.pathname === "/privacy-statement/" || window.location.pathname === "/cookie-statement/" || window.location.pathname === "/datenschutzerklarung/" || window.location.pathname === "/cookie-erklarung/") {
					$container.hide();
				}
				else {
					TOL_showToestemming();
					$.magnificPopup.open({
						mainClass: 'cookiewall',
						showCloseBtn: false,
						enableEscapeKey: false,
						closeOnBgClick: false,
						items: {
							type: 'inline',
							src: '#cookiebar-container'
						}
					});
				}
			} else {
				$container.hide();
			}
		} else {
			(function (w, d, o) {
				var e = d.createElement('script');
				e.async = true;
				e.src = (container.data('url') || 'https://jouw.postnl.nl/widgets/cookie-widget/bootstrap.js?') +
					(new Date().getTime());
				var s = d.getElementsByTagName('script')[0];
				s.parentNode.insertBefore(e, s);
				e.onload = function () {
					try {
						w.PostNL = w.PostNL || {};
						w.PostNL.CookieWidget = new w.CookieWidget.Bootstrap(d, e,
							o).getAPI();
					} catch (e) {
						console.error('Error starting CookieWidget');
						console.error(e);
					}
				};
			})(window, document, {
				Element: container,
				Language: container.data('lang'),
				Events: {
					Loaded: function (api) {
						window.PostNL.initSocialSharingButtons && window.PostNL.initSocialSharingButtons(api);
					}
				}
			});
		}
	}($('#cookie-notice')));

	/**
	 * Adds a collapsible behavior to elements
	 * @param {object} [options] Additional settings for the collapsible:
	 * - toggleSelector    {string}   The selector to find the collapsible toggle, defaults to '.collapsible-toggle'.
	 * - collapsedClass    {string}   Class applied to collapsible target when hidden/toggled/collapsed, defaults to 'collapsed'.
	 * - toggledClass      {string}   Class applied to collapsible toggle when hidden/toggled/collapsed, defaults to 'toggled'.
	 * - animationDuration {int}      The duration of the show/hide animation, defaults to 400.
	 * - animationEasing   {string}   Easing function used by the animation, defaults to 'swing'.
	 * - toggleFunction    {Function} Function to toggle the collapsible target, defaults to $.fn.slideToggle.
	 * - hideFunction      {Function} Function to hide the collapsible target after initialisation, defaults to $.fn.hide.
	 * - toggleText        {string}   String for the default or 'open' state of the toggle
	 * - toggledText       {string}   String for hte toggled or 'closed' state of the toggle
	 * - updateOnResize    {boolean}  Set to false to disable the recalculation of the height of the collapsible when the window resizes.
	 *
	 * @returns {jQuery}
	 */
	$.fn.collapsible = function (options) {
		var settings = $.extend({}, {
			toggleSelector: '.collapsible-toggle',
			collapseOthers: 'collapse-others',
			collapsedClass: 'collapsed',
			togglingClass: 'toggling',
			toggledClass: 'toggled',
			animationDuration: 400,
			animationEasing: 'swing',
			toggleFunction: $.fn.slideToggle,
			hideFunction: $.fn.hide,
			showFunction: $.fn.show,
			toggleText: null,
			toggledText: null,
			updateOnResize: true
		}, options),
			$window = $(window),
			$html = $(document.documentElement),
			windowWidth = $window.width(),
			toggles = $(settings.toggleSelector),
			collapsibles = this,
			updateTimer;

		if (this.length && $html.data('collapsible-observer') !== settings.toggleSelector) {
			$html
				.data('collapsible-observer', settings.toggleSelector)
				.on('click', settings.toggleSelector, function (event) {
					var toggle = $(this),
						collapsible = toggle.data('collapsible');

					event.preventDefault();
					if (collapsible) {
						collapsible.trigger('toggle.collapsible');
					}
				});
		}

		collapsibles.each(function () {
			var collapsible = $(this),
				toggle = (function () {
					var id = collapsible.attr('id'),
						elements = [];

					if (id) {
						elements = toggles.filter('[href="#' + id + '"]');
					}

					if (!elements.length) {
						elements = collapsible.prevAll(settings.toggleSelector).first();
					}

					return elements;
				}()),
				padding = collapsible.css(['padding-top', 'padding-bottom']),
				collapsed;

			function updateText() {
				if (settings.toggleText && settings.toggledText) {
					toggle.html(collapsed ? settings.toggledText : settings.toggleText);
				}
				collapsible.attr('aria-hidden', collapsed);
			}

			if (toggle.length) {
				toggle.data('collapsible', collapsible);
				collapsible.data('collapsible-toggle', toggle);
				collapsed = collapsible.hasClass(settings.collapsedClass);

				collapsible.on('hide.collapsible', function () {
					settings.hideFunction.apply(collapsible);
					collapsed = true;
					updateText();
				});

				collapsible.on('show.collapsible', function () {
					settings.showFunction.apply(collapsible);
					collapsed = false;

					updateText();
				});

				collapsible.on('toggle.collapsible', function (event, bubble) {
					collapsed = !collapsed;
					toggle.toggleClass(settings.toggledClass, collapsed);
					toggle.addClass(settings.togglingClass);

					settings.toggleFunction.apply(collapsible.stop(), [settings.animationDuration, settings.animationEasing, function () {
						collapsible.toggleClass(settings.collapsedClass, collapsed);
						toggle.removeClass(settings.togglingClass);
					}]);

					if (bubble != false && collapsible.hasClass(settings.collapseOthers)) {
						collapsible.parents('.block').find('.' + settings.collapseOthers).not(collapsible).not('.collapsed').trigger('toggle.collapsible', [false]);
					}

					if ($(this).parents('.faq-detail-component').length && !collapsed) {
						document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
							detail: {
								name: "in_page_interaction",
								in_page: {
									"name": $(this).prev().text(),
									"category": "faq",
									"location": "body"
								}
							}
						})
						);
					}

					updateText();
				});

				/**
				 * Recalculates the height of the collapsible which is fixed by jQuery
				 */
				collapsible.on('update.collapsible', function () {
					if (collapsed) {
						collapsible.css(padding);
						settings.showFunction.apply(collapsible);
					}

					collapsible
						// Reset height
						.css('height', 'auto')
						// and fixate it again
						.css('height', collapsible.height());

					if (collapsed) {
						settings.hideFunction.apply(collapsible);
					}
				});

				if (collapsed) {
					settings.hideFunction.apply(collapsible);
				}
				toggle.toggleClass(settings.toggledClass, collapsed);
				updateText();
			}
		});

		if (settings.updateOnResize) {
			addResizeHandler(function () {
				var newWindowWidth = $window.width();
				if (newWindowWidth !== windowWidth) {
					window.clearTimeout(updateTimer);
					updateTimer = window.setTimeout(function () {
						collapsibles.trigger('update.collapsible');
						windowWidth = newWindowWidth;
					}, 500);
				}
			});
		}

		return collapsibles;
	};

	/**
	 * Equalizes the same property on each item in each scope resulting in equal values for each 'row' in the scope.
	 * @param {object} [options]
	 * - scopeSelector           {string}     The selector used to determine each 'column'.
	 * - itemSelector            {string}     The selector used to determine each 'row'.
	 * - readProperty            {string}     The CSS property which is read and fed to the equalisation function.
	 * - applyProperty           {string}     The CSS property which is applied to each item with the equalised value.
	 * - resetApplyProperty      {int|string} The apply property is reset to this value before the read property is polled.
	 * - resizingClass           {string}     The container receives this class before the items are polled. This allows you
	 *                                        to use CSS to, for example, undo absolute positioning of specific items.
	 * - equalisationFunction    {Function}   Function used to calculate the value which is applied to each item in a row.
	 *                                        The function receives an array of polled values. Defaults to Math.max().
	 * - firstEqualisationDelay  {int}        The first equalisation is delayed by this amount of milliseconds.
	 * - resizeEqualisationDelay {int}        On window resize, delay the equalisation by this amount of milliseconds.
	 * - mode                    {string}     Use 'flat' to simply equalize all items or 'rows' to equalize each 'row' in each 'column'.
	 *
	 * @returns jQuery
	 */
	$.fn.equalizeStyle = function (options) {
		var defaults = {
			scopeSelector: '.column',
			itemSelector: '.row',
			readProperty: 'height',
			applyProperty: 'min-height',
			defaultPropertyValue: 0,
			resetApplyPropertyValue: 0,
			resizingClass: 'resizing',
			mode: 'columned',
			equalisationFunction: function (rowValues) {
				return Math.max.apply(Math, rowValues);
			},
			firstEqualisationDelay: 500,
			resizeEqualisationDelay: 50
		},
			settings = $.extend({}, defaults, options),
			containers = $(this),
			resizeTimer;

		containers.each(function () {
			var container = $(this),
				scopeSelector = container.data('eq-scope') || settings.scopeSelector,
				itemSelector = container.data('eq-item') || settings.itemSelector,
				mode = container.data('eq-mode') || settings.mode,
				when = container.data('eq-when'),
				columns, columnCount, items, itemCount;

			if (mode === 'flat') {
				items = container.find(itemSelector).map(function () {
					return $(this);
				});
				columnCount = items.length;
				itemCount = 1;
			} else {
				columns = container.find(scopeSelector);
				columnCount = columns.length;
				items = columns.map(function () {
					return $(this).find(itemSelector);
				});
				itemCount = items[0].length;
			}

			function equalize() {
				var x, y, rowValues, rowItems, item, itemHeight, rowMax;
				if (when && !matchedMedia().matches(when)) {
					for (y = 0; y < itemCount; y++) {
						for (x = 0; x < columnCount; x++) {
							items[x].eq(y).css(settings.applyProperty, settings.defaultPropertyValue);
						}
					}
					return;
				}

				// add the resizing class to be able to prepare the element to be measured using CSS:
				container.addClass(settings.resizingClass);
				for (y = 0; y < itemCount; y++) {
					rowValues = [];
					rowItems = $();
					// Collect each row
					for (x = 0; x < columnCount; x++) {
						item = items[x].eq(y);
						rowItems = rowItems.add(item);
						// reset the (possibly) previous applied property to the default value:
						item.css(settings.applyProperty, settings.resetApplyPropertyValue);
						// now read the 'read property' and store it:
						itemHeight = parseInt(item.css(settings.readProperty), 10);
						if (!isNaN(itemHeight)) {
							rowValues.push(itemHeight);
						}
					}
					// determine the maximum value:
					rowMax = settings.equalisationFunction(rowValues);
					// apply the max property to each item in the row:
					rowItems.css(settings.applyProperty, rowMax);
				}
				// remove the resizing class again:
				container.removeClass(settings.resizingClass);
			}

			container.on('resizeContainers.eqStyle', equalize);
		});

		// Delay the first equalize call for
		window.setTimeout(function () {
			containers.trigger('resizeContainers.eqStyle');
		}, settings.firstEqualisationDelay);

		addResizeHandler(function () {
			containers.trigger('resizeContainers.eqStyle');
		});

		return containers;
	};

	/**
	 * Collapsible list
	 */
	$.fn.collapsibleList = function () {
		var lists = $(this).each(function () {
			var list = $(this),
				items = list.children(),
				limit = window.parseInt(list.data('limit')),
				others = items.length - limit,
				moreText = list.data('more'),
				lessText = list.data('less'),
				collapsed = false,
				defaultHeight,
				collapsedHeight,
				moreLink;

			function setStateHeights() {
				list.css('height', 'auto');
				defaultHeight = list.height();
				items.each(function (i, item) {
					item = $(item);
					if (i >= limit) {
						item.hide();
					} else {
						item.show();
					}
				});

				collapsedHeight = list.height();
				if (!collapsed) {
					list.height('auto');
				}
				items.show();
			}

			function updateToggle() {
				moreLink
					.toggleClass('collapsed', collapsed)
					.text(collapsed ? (moreText + ' (' + others + ')') : lessText);
			}

			function toggle(force) {
				force = force !== undefined ? force : collapsed;
				list.stop().animate({
					height: force ? collapsedHeight : defaultHeight
				}, 400, updateToggle);
			}

			if (limit && items.length > limit) {
				setStateHeights();
				moreLink = $('<a>', {
					'class': 'more-link',
					'href': '#'
				}).on('click', function (event) {
					event.preventDefault();
					toggle(!collapsed);
					collapsed = !collapsed;
				});

				$('<p>', {
					'class': 'collapsible-list-toggle'
				}).append(moreLink).insertAfter(list);

				if (list.hasClass('collapsed')) {
					collapsed = true;
					toggle();
				}

				updateToggle();

				list.on('update.collapsibleList', function () {
					setStateHeights();
					list.height(collapsed ? collapsedHeight : defaultHeight);
				});
			}
		}), timer;

		//addResizeHandler
		addResizeHandler(function () {
			window.clearTimeout(timer);
			timer = window.setTimeout(function () {
				lists.trigger('update.collapsibleList');
			}, 500);
		});
	};

	/**
	 * Conditionally display an element based on the state or value of other elements.
	 *
	 * The settings are retrieved from data-* attributes from the element.
	 * - data-cd-fields="[selector]" - A selector specifying the elements to be checked e.g. "input[name=foo]".
	 * - data-cd-filter="[filter]" - An optional filter which is applied on each change on the fields e.g. ":checked"
	 * - data-cd-values="value1, value2" - A list of field values for which the element is displayed.
	 * - data-cd-value="value" - Same as 'values' but doesn't split the string into multiple values.
	 *
	 * @returns {jQuery}
	 */
	$.fn.conditionalDisplay = function () {
		return $(this).each(function () {
			var element = $(this),
				fields = $(element.data('cd-fields')),
				filter = element.data('cd-filter'),
				values = element.data('cd-values'),
				visible;

			if (!values) {
				values = element.data('cd-value');
			}
			values = values ? values.split(/[,\s]{1,}/) : [];

			function isVisible() {
				var filtered = fields;
				if (filter) {
					filtered = filtered.filter(filter);
				}
				if (values) {
					filtered = filtered.filter(function () {
						return values.indexOf($(this).val()) >= 0;
					});
				}
				return !!filtered.length;
			}

			fields
				.on('change keyup', function () {
					var currentState = visible;
					visible = isVisible();
					element.toggleClass('hidden', !visible);
					if (visible !== currentState) {
						element.trigger('change.conditionalDisplay');
					}
				})
				.trigger('change', [false]);
		});
	};

	/**
	 * A date range select behavior, enables or disables the options in the other select element according to the value
	 * selected in this select.
	 *
	 * @param {object} [options]
	 * - isOptionDisabledMethod {Function} A function that determines whether an option should be disabled. See it's
	 *   documentation for more information.
	 * - toggleOptionMethod {Function} The function used to enable or disable an option. See it's documentation for more
	 *   information.
	 *
	 * @returns {jQuery}
	 */
	$.fn.dateRangeSelect = function (options) {
		var defaults = {
			/**
			 * Determines whether this option should be disabled. The function is bound to the extended option element.
			 * @param {int} value The value of the option
			 * @param {int} otherValue The value of the other select
			 * @param {object} parameters An object literal with the following properties:
			 * - select {jQuery} The select element,
			 * - index {int} The index of this option
			 * - options {jQuery} All options in the select element
			 * - range {string} Either 'from' or 'to' depending on the role of this select
			 * - other {jQuery} The 'other' select element
			 *
			 * @returns {boolean}
			 */
			isOptionDisabledMethod: function (value, otherValue, parameters) {
				value = parseInt(value, 10);
				otherValue = parseInt(otherValue, 10);

				return (parameters.range === 'from' && value > otherValue)
					|| (parameters.range === 'to' && value < otherValue);
			},
			/**
			 * The function used to enable or disable an option. The function is bound to the extended option
			 * element. Override this to allow enabling or disabling an option using a select box replacement plugin.
			 * @param {boolean} disabled Whether the option should be disabled
			 * @param {object} parameters An object literal with the following properties:
			 * - select {jQuery} The select element
			 * - index {int} The index of this option
			 * - options {jQuery} All options in the select element
			 * - range {string} Either 'from' or 'to' depending on the role of this select
			 * - other {jQuery} The 'other' select element
			 */
			toggleOptionMethod: function (disabled, parameters) {
				this.prop('disabled', disabled);
			}
		},
			settings = $.extend({}, defaults, options);

		return $(this).each(function () {
			var select = $(this),
				$options = select.find('option'),
				range = select.data('range') || 'from',
				other = $(select.data(range === 'from' ? 'to' : 'from'));

			select.on('update.dateRangeSelect', function () {
				var otherValue = other.val();

				$options.each(function (index) {
					var option = $(this),
						value = option.attr('value'),
						parameters = {
							select: select,
							options: $options,
							range: range,
							other: other,
							index: index
						},
						disabled;

					if (value !== undefined) {
						disabled = settings.isOptionDisabledMethod.call(option, value, otherValue, parameters);
						settings.toggleOptionMethod.call(option, disabled, parameters);
					}
				});
			});

			select.on('change', function () {
				other.trigger('update.dateRangeSelect');
			});
		});
	};

	/**
	 * Converts the given elements to fake select elements
	 * @param {Object} [options]
	 * @returns {jQuery}
	 */
	$.fn.fakeSelect = function (options) {
		var defaults = {
			componentSelectors: {
				value: '.select-value',
				list: '.select-list',
				listItem: '.select-option'
			},
			classes: {
				open: 'is-open',
				closed: 'is-closed',
				selected: 'is-selected'
			},
			callbacks: {
				opened: $.noop,
				closed: $.noop,
				toggled: $.noop,
				changed: $.noop
			},
			outsideEvents: 'click touchend'
		},
			settings = $.extend({}, defaults, options),
			dataKey = 'FakeSelect',
			$document = $(document);

		/**
		 * Creates a fake select from the given element
		 * @param {jQuery} $container
		 * @constructor
		 */
		function FakeSelect($container) {
			var self = this;

			this.settings = settings;

			this.$container = $container;
			this.$value = $container.find(settings.componentSelectors.value);
			this.value = this.$value.html();
			this.$list = $container.find(settings.componentSelectors.list);
			this.$items = this.$list.find(settings.componentSelectors.listItem);
			this.$selectedItem = this.$items.filter('.' + settings.classes.selected);

			if (!this.$selectedItem.length) {
				this.$selectedItem = this.$items.filter(function () {
					return self.value === self.valueFromItem($(this));
				});
			}
			if (!this.$selectedItem.length) {
				this.$selectedItem = this.$items.first();
			}
			if (this.$selectedItem.length && !this.$selectedItem.hasClass(settings.classes.selected)) {
				this.select(this.$selectedItem);
			}

			this.isOpen = $container.hasClass(settings.classes.open);
			this.toggle(this.isOpen);

			this.$value.on('touchstart', $.noop);

			this.$list.on('mouseleave', function () {
				self.close();
			});

			$container
				.on('click', settings.componentSelectors.value, function () {
					self.toggle();
				})
				.on('click', settings.componentSelectors.listItem, function () {
					if (self.select($(this))) {
						var cookie = new Cookie('Language');
						cookie.path = '/';
						cookie.write($(this).find("span").attr("class").replace("language", "").trim());
						self.close();
					}
				})
				.data(dataKey, this);
		}

		/**
		 * Opens the select
		 * @returns {Object} A Promise
		 */
		FakeSelect.prototype.open = function () {
			var $d = $.Deferred(),
				self = this,
				currentState = this.isOpen;

			this.$container.addClass(settings.classes.open).removeClass(settings.classes.closed);
			this.isOpen = true;
			if (!currentState) {
				settings.callbacks.opened(this);
			}

			window.setTimeout(function () {
				self.delayedCloseHandler = function (event) {
					if (!$.contains(self.$container.get(0), event.target)) {
						self.close();
					}
					self.delayedCloseHandler = null;
				};
				$document.one(settings.outsideEvents, self.delayedCloseHandler);
			}, 1);
			$d.resolve();
			return $d.promise();
		};

		/**
		 * Closes the select
		 * @returns {Object} A Promise
		 */
		FakeSelect.prototype.close = function () {
			var $d = $.Deferred(),
				currentState = this.isOpen;

			if (this.delayedCloseHandler) {
				$document.off(settings.outsideEvents, this.delayedCloseHandler);
			}
			this.$container.removeClass(settings.classes.open).addClass(settings.classes.closed);
			this.isOpen = false;
			if (currentState) {
				settings.callbacks.closed(this);
			}
			$d.resolve();
			return $d.promise();
		};

		/**
		 * Toggles the select
		 * @param {boolean} [state]
		 * @returns {Object} A Promise
		 */
		FakeSelect.prototype.toggle = function (state) {
			if (state === undefined) {
				state = !this.isOpen;
			}
			return state ? this.open() : this.close();
		};

		/**
		 * Selects the given item
		 * @param {number|jQuery} $item
		 * @returns {boolean} success
		 */
		FakeSelect.prototype.select = function ($item) {
			if ($.type($item) === 'number') {
				$item = this.$items.get($item);
			}
			if (this.$items.index($item) >= 0) {
				this.$items.removeClass(settings.classes.selected);
				$item.addClass(settings.classes.selected);
				this.$value.html(this.valueFromItem($item));
				settings.callbacks.changed(this, $item);
				return true;
			}
			return false;
		};

		/**
		 * Returns the string value from the given item
		 * @param {jQuery} $item
		 * @returns {String|null}
		 */
		FakeSelect.prototype.valueFromItem = function ($item) {
			if (this.$items.index($item) >= 0) {
				return $item.html();
			}
			return null;
		};

		return this.each(function () {
			var $container = $(this),
				instance = $container.data(dataKey);
			return instance || new FakeSelect($(this));
		});
	};
}(jQuery));

/**
 * DOM:loaded event
 */
jQuery(function ($) {
	'use strict';

	var $window = $(window),
		$html = $(document.documentElement),
		$body = $(document.body),
		isTouch = (window.ontouchstart !== undefined) || (!!window.DocumentTouch && document instanceof window.DocumentTouch),
		isMobile = (function () {
			function poll() {
				return $window.width() <= (660 - 15);
			}

			$window.on('resize', debounce(function () {
				isMobile = poll();
			}, 100));
			return poll();
		}()),
		// MenuOverlay is defined in header.js
		Overlay = window.MenuOverlay || {
			show: $.noop,
			hide: $.noop
		},
		tap = isTouch ? 'touchstart' : 'click',
		isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;

	$html.toggleClass('is-ios', isIOS);


	(function (welcome) {
		var
			renderUserInfo = function (user_info) {
				welcome.renderHandleBars({
					user: user_info
				})
			};
		if (welcome.length) {
			if (welcome.data('greeting')) {
				welcome.renderHandleBars({
					greeting: welcome.data('greeting').split(',')[Math.floor((new Date()).getHours() / 6)]
				});
				linearGradientHomePageBanner();
			}
			if (window.userDetails) {
				renderUserInfo(window.userDetails.user_info);
			} else {
				$window
					.on('userDetails', renderUserInfo);
			}
		}
	})($('.full-width.hero-image.page-title h1.title:has(script)'));

	/**
	 * Determine the js folder for the correct paths
	 * @type {string|jsFolder}
	 */
	window.jsFolder = window.jsFolder || (function () {
		var src = $('script[src*="\/main"]').first().attr('src'),
			match = src ? src.match(/(.*)main.*$/i) : null;
		if (match) {
			return match[1];
		}
		return '';
	}());

	/**
	 * Magnific popup translations
	 */
	if ($.magnificPopup) {
		$.extend(true, $.magnificPopup.defaults, {
			tClose: i18n.get('lightbox.close'), // Alt text on close button
			tLoading: i18n.get('lightbox.loading'), // Text that is displayed during loading. Can contain %curr% and %total% keys
			gallery: {
				tPrev: i18n.get('lightbox.previous'), // Alt text on left arrow
				tNext: i18n.get('lightbox.next'), // Alt text on right arrow
				tCounter: i18n.get('lightbox.counter') // Markup for "1 of 7" counter
			},
			image: {
				tError: i18n.get('lightbox.errors.image') // Error message when image could not be loaded
			},
			ajax: {
				tError: i18n.get('lightbox.errors.ajax') // Error message when ajax request failed
			}
		});
	}

	// initialize responsive tables:
	$('table:not(.skip-resonsiveTable)').each(function () {
		var
			fadeWidth,
			table = $(this),
			scroller = table
				.wrap('<div class="scroller"/>')
				.parent(),
			container = scroller
				.wrap('<div class="table-scroll-container"></div>')
				.parent(),
			fadeLeft = $('<div class="fade-gradient-left"/>'),
			fadeRight = $('<div class="fade-gradient-right"/>'),
			checkScrollables = function () {
				var
					scrollLeft = scroller.scrollLeft(),
					scrollRight = table.width() - scroller.width() - scrollLeft;
				// Move fade away when scrolling nears end
				fadeLeft.css({ transform: 'translateX(' + Math.min(2 * scrollLeft - fadeWidth, 0) + 'px)' });
				fadeRight.css({ transform: 'translateX(' + Math.max(-2 * scrollRight + fadeWidth, 0) + 'px)' });
			};
		container
			.prepend(fadeLeft)
			.append(fadeRight);
		fadeWidth = fadeLeft.width(); // Assume both left and right have same width
		scroller.scroll(debounce(checkScrollables, 10));
		$window.resize(debounce(checkScrollables, 200));
		checkScrollables();
	});

	// initialize responsive images:
	$('img.responsive').responsiveImage();
	// initialize conditional display elements:
	$('.conditional-display').conditionalDisplay();
	// initialize killer apps:
	if ($.fn.killerApp !== undefined) {
		$('.killer-app').killerApp({
			onActivate: function () {
				Overlay.show('killer-app');
			},
			onDeactivate: function () {
				Overlay.hide('killer-app');
			}
		});
	}
	if ($.fn.killerAppOld !== undefined) {
		$('.killer-app-old').killerAppOld({
			onActivate: function () {
				Overlay.show('killer-app');
			},
			onDeactivate: function () {
				Overlay.hide('killer-app');
			}
		});
	}

    /**
     * Equal height util
     * Function has been added to window to be able to re-execute the function.
     */
	function equalHeight() {
		// initialize equal height elements
		$('.equal-height').equalizeStyle();
	}

	equalHeight();

	window.equalHeight = equalHeight;

	// initialize fake selects:
	$('.fake-select').fakeSelect();

	if ($body.hasClass('full-width-header')) {
		(function ($swoosh) {
			var swooshOffset = $swoosh.offset().top;
			$window.on('scroll', debounce(function () {
				$html.toggleClass('scrolled-down', $window.scrollTop() > swooshOffset);
			}, 50, { 'maxWait': 100 }));
		}($('.swoosh')));
	}

	if (Modernizr.bgsizecover) {
		$('.cover-image').each(function () {
			var container = this,
				$container = $(container).addClass('cover-applied'),
				$desktopImage = $container.find('> .image:not(.image-tablet)').hide(),
				$tabletImage = $container.find('> .image.image-tablet').hide(),
				updateBgImg = function ($image) {
					$container.css({ 'background-image': 'url(' + $image.attr('src') + ')' });
				};

			if ($tabletImage.length) {
				var
					resizeHandler = function () {
						updateBgImg($(window).width() <= 660 ? $tabletImage : $desktopImage);
					}
				addResizeHandler(resizeHandler);
				resizeHandler();
			} else {
				updateBgImg($desktopImage);
			}

			function isInViewport(element, options) {
				var boundingRect = (options && options.rect) ? options.rect : element.getBoundingClientRect(),
					top = boundingRect.top,
					bottom = boundingRect.bottom,
					left = boundingRect.left,
					right = boundingRect.right,
					settings = options || { 'tolerance': 0 },
					isVisible = false,
					$viewport = (options && options.$viewport) ? options.$viewport : $window,
					viewportHeight = (options && options.viewportHeight) ? options.viewportHeight : $viewport.height(),
					viewportWidth = (options && options.viewportWidth) ? options.viewportWidth : $viewport.width();

				if (settings.tolerance < 0) {
					settings.tolerance = viewportHeight + settings.tolerance;
				}

				if (right <= 0 || left >= viewportWidth) {
					return isVisible;
				}

				isVisible = settings.tolerance ? !!(top <= settings.tolerance && bottom >= settings.tolerance) : !!(bottom > 0 && top <= viewportHeight);

				return isVisible;
			}

			if ($container.hasClass('animate-on-scroll')) {
				//$window.on('scroll', debounce(function () {
				$window.on('scroll', function () {
					var boundingRect = container.getBoundingClientRect(),
						viewportHeight = $window.height(),
						viewportWidth = $window.height(),
						startPosition = 50,
						rectCenter = boundingRect.top + (boundingRect.height / 2),
						offset, diff;

					// console.info(boundingRect);

					if (isInViewport(container, {
						rect: boundingRect,
						viewportHeight: viewportHeight,
						viewportWidth: viewportWidth,
						tolerance: 0
					})) {

						offset = (viewportHeight / 2) - rectCenter;
						diff = 30 * (offset / viewportHeight);
						$container.css('background-position-y', (startPosition + diff) + '%');
					}
				});
				//}, 100, {'maxWait': 150}));
			}
		});
	}

	/**
	 * Initialize collapsible elements:
	 * Collapsible elements can have an optional attribute `data-collapsible-show-items` which alters the collapsible
	 * to instead of collapsing to a height of `0` the collapsible will show a minimum amount of items when collapsed.
	 * The `data-collapsible-item-item` attribute contains a selector for the items to measure the height of. This
	 * attribute is only required when `collapsible-show-items` is set.
	 * The `data-collapsible-item-scope` attribute contains a selector for an optional scope in which items are
	 * searched for. The highest value for each scope is then used as the collapsed height of the collapsible.
	 */
	$('.collapsible').each(function () {
		var collapsible = $(this),
			settings = {
				toggleFunction: $.fn.slideToggle,
				hideFunction: $.fn.hide,
				showFunction: $.fn.show
			},
			showItems = collapsible.data('collapsible-show-items') || 0,
			itemSelector = collapsible.data('collapsible-item'),
			scopeSelector = collapsible.data('collapsible-item-scope'),
			defaultHeight = collapsible.height(),
			collapsibleWidth = collapsible.width(),
			collapsed = false,
			collapsedHeight = 0;

		function hide() {
			collapsed = true;
			return collapsible.height(collapsedHeight);
		}

		function show() {
			collapsed = false;
			return collapsible.height(defaultHeight);
		}

		// Do we want to show a minimum amount of items:
		if (showItems) {
			// calculate the collapsed height for the number of items we want to show
			collapsedHeight = (function () {
				var scopes = scopeSelector ? collapsible.find(scopeSelector) : collapsible,
					heights = scopes.map(function () {
						var scope = $(this),
							items = scope.find(itemSelector),
							height = 0;
						items.each(function (i) {
							var item = $(this);
							if (i < showItems) {
								height += (window.parseFloat(item.outerHeight()) + window.parseFloat(item.css('margin-top'))
									+ window.parseFloat(item.css('margin-bottom')));
								return true;
							}
							return false;
						});
						return height;
					});
				return Math.max.apply(Math, $.makeArray(heights));
			}());
			// custom show/hide functions which use our custom collapsed height
			settings.hideFunction = hide;
			settings.showFunction = show;
			// custom toggle function which uses our custom collapsed height
			settings.toggleFunction = function () {
				collapsible.stop().animate({
					'height': collapsed ? defaultHeight : collapsedHeight
				});
				collapsed = !collapsed;
			};
			// set a resize handler which updates the default height when the width of the collapsible has changed.
			$window.on('resize', debounce(function () {
				var newWidth = collapsible.width();
				if (newWidth !== collapsibleWidth) {
					defaultHeight = collapsible.height('auto').height();
					if (collapsed) {
						hide();
					} else {
						show();
					}
				}
			}, 1000));
		}

		collapsible.collapsible(settings);

		if (showItems) {
			collapsible.data('collapsible-toggle').addClass('toggling');
		}
	});

	$('dl.collapsible-items dd').collapsible({
		toggleSelector: 'dt'
	});

	$('.collapsible-list').collapsibleList();

	if ($.fn.selectBoxIt !== undefined) {
		// The date range behavior combined with the custom select box plugin
		$('.date-range').dateRangeSelect({
			toggleOptionMethod: function (disabled, parameters) {
				var api = parameters.select.data('selectBox-selectBoxIt');
				if (api) {
					api[disabled ? 'disableOption' : 'enableOption'](parameters.index);
				}
			}
		});
		// Initialize the selectBoxIt plugin
		var
			intervalId,
			disabledState = [],
			maxChecks = 30,
			selects = $('select.input');
		selects
			.each(function (selectNr) {
				disabledState[selectNr] = this.disabled;
			})
			.selectBoxIt({
				copyClasses: 'container'
			})
			// Enable selects in webpower
			.closest('form').find(':radio[data-condition], :checkbox[data-condition]')
			.on('change', function () {
				var
					checkNr = 0;
				clearInterval(intervalId);
				intervalId = setInterval(function () {
					checkNr++;
					selects.each(function (selectNr) {
						if (this.disabled !== disabledState[selectNr]) {
							$(this).selectBoxIt('refresh');
							disabledState[selectNr] = this.disabled;
						}
					});
					if (checkNr >= maxChecks) {
						clearInterval(intervalId);
					}
				}, 80);
			});

		// Select inputs with postweb styling
		// They are full width thus auto width is set to false
		$('.postweb select.input').each(function () {
			$(this).data('selectBox-selectBoxIt').setOptions({ autoWidth: false });
		});

	} else {
		// Date range behavior on a native select
		$('.date-range').dateRangeSelect();
	}

	/**
	 * In-page navigation interaction
	 */
	$('nav.sub-menu').each(function () {
		var menu = $(this),
			subMenus = menu.find('.children'),
			openMenus = menu.find('a.active').parents('.children');

		// create menu toggles and hide inactive sub menu's
		subMenus.each(function () {
			var subMenu = $(this),
				parent = subMenu.prev(),
				open = parent.hasClass('active') || openMenus.index(subMenu) >= 0;

			subMenu.before($('<a>', {
				'class': 'menu-toggle' + (open ? ' open' : ''),
				'href': parent.attr('href'),
				'html': open ? '+' : '-'
			}));
			if (!open) {
				subMenu.hide();
			}
		});

		// Toggle observer
		menu.on(tap, '.menu-toggle', function (event) {
			var toggle = $(this),
				subMenu = toggle.siblings('.children');
			event.preventDefault();
			toggle
				.html(subMenu.is(':visible') ? '+' : '-')
				.toggleClass('open');
			subMenu.stop().slideToggle('fast');
		});
	});

	/**
	 * Collapsible feature lists
	 */
	(function () {
		var collapsibleFeatures = $('.collapsible-features').each(function (i) {
			var collapsible = $(this).attr('id', 'feature-list-' + i),
				toggleId = 'feature-toggle-' + i;

			collapsible.after($('<a>', {
				'class': 'toggle',
				'id': toggleId,
				'href': '#feature-list-' + i,
				'text': '+'
			})).collapsible({
				toggleSelector: '#' + toggleId,
				toggleText: collapsible.data('toggle-open') || '+',
				toggledText: collapsible.data('toggle-close') || '-'
			});
		}), currentState;

		function updateState() {
			if (isMobile !== currentState) {
				currentState = isMobile;
				collapsibleFeatures.trigger(isMobile ? 'hide.collapsible' : 'show.collapsible');
			}
		}

		if (isMobile) {
			collapsibleFeatures.trigger('hide.collapsible');
		}
		$window.on('resize', debounce(updateState, 100, { 'maxWait': 200 }));
		updateState();
	}());

	// Animated scroll
	window.animatedScrollTo = (function () {
		var scrollElement = $html.add($body);

		function animatedScrollTo(y, hash) {
			scrollElement.animate({ scrollTop: y }, {
				complete: function () {
					if (hash) {
						window.location.hash = hash;
					}
				}
			});
		}

		return animatedScrollTo;
	}());

	/**
	 * Generate an overlay on small screens which reminds the user that he's leaving this website and visiting a site
	 * that might not be optimized for mobile.
	 * @param {jQuery} link The link element which was clicked.
	 * @returns {boolean} True when the pop up is shown, and false when it's not.
	 */
	function mobileExitConfirm(link) {
		var allowRememberChoice = link.data('remember-choice') !== 'false',
			cookie = new Cookie('confirm-not-responsive-exit'),
			rememberInput, popup, buttons;

		if ($window.width() > 768 || cookie.value === 'false') {
			return false;
		}

		popup = $('<div>', {
			'class': 'confirm-content'
		})
			.append($('<h1>', {
				'class': 'title',
				'text': i18n.get('exit-confirm.title')
			}))
			.append($('<p>', {
				'class': 'message',
				'text': i18n.get('exit-confirm.text')
			}));

		if (allowRememberChoice) {
			rememberInput = $('<input>', {
				'class': 'input',
				'type': 'checkbox'
			});
			popup.append($('<p>', {
				'class': 'remember-choice form-row checkbox'
			}).append($('<label>', {
				'class': 'label',
				'text': i18n.get('exit-confirm.remember-choice')
			}).prepend(rememberInput)));
		}

		buttons = $('<p>', {
			'class': 'buttons'
		}).appendTo(popup).on('click', '.button', function (event) {
			if ($(this).hasClass('cancel')) {
				event.preventDefault();
			} else {
				if (allowRememberChoice && rememberInput.prop('checked')) {
					// set the cookie value to false (don't confirm unresponsive exits)
					cookie.write('false');
				}
			}

			$.magnificPopup.close();
		});

		buttons
			.append($('<a>', {
				'class': 'link previous cancel button',
				'href': window.location.href,
				'text': i18n.get('exit-confirm.cancel')
			}))
			.append($('<a>', {
				'class': 'action button',
				'href': link.attr('href'),
				'target': link.attr('target'),
				'text': i18n.get('exit-confirm.proceed')
			}));

		$.magnificPopup.open({
			mainClass: 'lightbox-dialog lightbox-dialog',
			showCloseBtn: false,
			items: {
				type: 'inline',
				src: popup
			}
		});

		return true;
	}

	// fully clickable blocks:
	$html.on('click', '.clickable', function (event) {
		var link = $(event.currentTarget).find('a').first(),
			href = link.attr('href'),
			target = (link.attr('target') || '').toLowerCase();

		if (link.hasClass('mobile-exit-confirm')) {
			if (mobileExitConfirm(link)) {
				// mobile exit confirm is showing, do nothing.
				event.preventDefault();
				event.stopImmediatePropagation();
				return;
			}
		}

		if (target === '_blank') {
			window.open(href);
			event.preventDefault();
		} else {
			window.location.href = href;
		}
	});

	// Event handler for
	$html.on('click', '.mobile-exit-confirm', function (event) {
		var link = $(event.currentTarget);

		if (mobileExitConfirm(link)) {
			// mobile exit confirm is showing, do nothing.
			event.preventDefault();
			event.stopImmediatePropagation();
		}
	});

	// Anchor buttons
	$html.on('click', '.button', function (event) {
		var href = $(this).attr('href'), target;
		if (href && href.match(/^#.*/)) {
			target = $(href);
			if (target.length) {
				event.preventDefault();
				window.animatedScrollTo(target.offset().top, target.attr('id'));
			}
		}
	});

	(function () {
        /**
         * Hashes to remove, '' for 'index.html#' and 'string' for index.html#string
         * @type {string[]}
         */
		var hashesToRemove = ['', 'top'];

        /**
         * Checks if the current hash is in the hashesToRemove list
         * if so, it uses replaceState to remove it from the URL.
         */
		function cleanHash() {
			var parts = window.location.href.split('#');

			if (parts.length > 1) {
				if (hashesToRemove.indexOf(parts[1]) >= 0) {
					window.history.replaceState(window.history.state, document.title, parts[0]);
				}
			}
		}

		if (window.history.replaceState) {
			$window.on('hashchange', cleanHash);
			cleanHash();
		}
	}());

	// Initialize auto complete
	(function () {
		var defaultSettings = {
			minChars: 1,
			deferRequestBy: 300,
			zIndex: 0,
			noCache: false,
			dataType: 'json'
		};

		if (!$.fn.autocomplete) {
			return;
		}
	}());

	/**
	 * Media galleries
	 */
	$('.gallery').each(function () {
		var gallery = $(this),
			galleryTitle = gallery.children('.title').html();

		gallery.magnificPopup({
			delegate: '.preview a',
			type: 'image',
			tLoading: gallery.data('loading-text') || i18n.get('gallery.loading-image'),
			mainClass: 'mfp-img-mobile gallery-lightbox',
			gallery: {
				enabled: true,
				navigateByImgClick: true,
				preload: [0, 1] // Will pre-load 0 - before current, and 1 after the current image
			},
			image: {
				tError: '<a href="%url%">' + (gallery.data('error-text') || i18n.get('gallery.errors.image')) + '</a>',
				titleSrc: function (item) {
					return $('<div>', {
						'class': 'caption-content'
					}).append([
						$('<strong>', {
							'class': 'caption-title',
							'text': galleryTitle
						}),
						$('<div>', {
							'class': 'caption-text',
							'html': item.el.closest('.item').find('.description, .buttons').clone()
						})
					]);
				}
			}
		});
	});

	/**
	 * Carousels
	 */
	if ($.fn.swiper) {
		(function () {
			var containers = $('.swiper-container').each(function () {
				var container = $(this),
					containerWidth = container.width();

				var prev = $('<button>', {
					'class': 'swiper-navigation previous',
					'text': '<'
				}).insertAfter(container);

				var next = $('<button>', {
					'class': 'swiper-navigation next',
					'text': '>'
				}).insertAfter(container);

				var swiperOptions = {
					mode: 'horizontal',
					loop: false,
					slideClass: 'carousel-item',
					slidesPerView: 'auto',
					calculateHeight: true,
					paginationClickable: true,
					nextButton: container.parent().find('.next'),
					prevButton: container.parent().find('.previous'),
				},
					// @var {Swiper} instance
					swiper, pagination;

				if (container.hasClass('swiper-with-pagination')) {
					pagination = $('<div>', {
						'class': 'swiper-pagination'
					}).insertAfter(container);
					swiperOptions.pagination = pagination.get(0);
				}

				container.addClass('initialized').swiper($.extend(swiperOptions, {}));
				swiper = container.data('swiper');
			});

			$window.on('resize', debounce(function () {
				containers.trigger('reinit.carousel');
			}, 500));
		}());
	}

	$('.change-news-date').on('change', function () {
		var year = $('#year').val();
		if (year != 0) {
			var month = $('#month').val();
		}
		var url = "?year=" + year + "&month=" + month;
		window.location.href = url;
	});

	/**
	 * Auto submitting fields (filter lists)
	 */
	$('.change-submit').on('change', function () {
		$(this).closest('form').trigger('submit');
	});

	/**
	 * Placeholder attribute fallback
	 */
	Modernizr.load({
		test: Modernizr.input.placeholder,
		nope: window.jsFolder + 'vendor/jquery.placeholder.min.js',
		callback: function () {
			$('textarea[placeholder], input[placeholder]').placeholder();
		}
	});

	$('body')
		.on('click', '.embeddedServiceHelpButton', function () {
			var
				salesForceOpenClass = 'salesforce-form-open',
				body = $('body').addClass(salesForceOpenClass);
			// start listening for dom change signalling closing of form
			new MutationObserver(function (mutationsList, observer) {
				mutationsList.forEach(function (mutation) {
					mutation.removedNodes.forEach(function (removedNode) {
						if ($(removedNode).hasClass('modalContainer')) {
							body.removeClass(salesForceOpenClass);
							observer.disconnect();
						}
					});
				});
			})
				.observe(
					$(this).closest('.slds-scope')[0], {
					childList: true
				}
				);
		});

	/**
	 * Call me now popup
     * Function has been added to window to be able to re-execute the function.
	 */
	function toCallMeNow() {

		$('.to-call-me-now').each(function (iterator) {
			var minBrowserWidth = 660,
				containerId = '',
				$container = null,
				$currentButton = $(this),
				$activeButton = false,
				defaultPushcallId = 'postnl_dm';

			function isMobileWidth() {
				return $window.width() < minBrowserWidth;
			}

			function openInLightBox() {
				$.magnificPopup.open({
					items: {
						src: '#' + containerId,
						type: 'inline'
					},
					callbacks: {
						close: function () {
							$activeButton.show();
							$activeButton = false;
							$('#generic-chat-container iframe').off('load.chat-frame');
						}
					},
					midClick: true,
					closeOnBgClick: false
				});
			}

			function toCallMeNowOnClick(event) {
				var section = $(this).parent().parent();
				if (section.hasClass("disabled") || section.hasClass("unavailable")) {
					return;
				}

				if ($activeButton.length && $activeButton !== $currentButton) {
					$activeButton.show();
				}

				$activeButton = $currentButton;
				$container.removeClass('mfp-hide');

				if (!isMobileWidth()) {
					openInLightBox();
				}
				else {
					$activeButton.hide();
				}

				event.preventDefault();
			}

			function onResize() {
				var $button, popup;

				if ($activeButton && $activeButton.length) {
					if (isMobileWidth()) {
						popup = $.magnificPopup.instance;
						if (popup) {
							if (popup.content) {
								$button = $activeButton;
								popup.close();
								$activeButton = $button;
								$activeButton.hide();
								$container.removeClass('mfp-hide');
							}
						}
					} else {
						$activeButton.show();
						openInLightBox();
					}
				}
			}

			function validateLabel(element) {
				var messages = {};
				if (element != null) {
					for (var i = 0; i < element.attributes.length; i++) {
						var attr = element.attributes[i];
						if (/^data-/.test(attr.nodeName) && value != '' && attr.nodeValue.substring(0, 16) != 'Missing Resource') {
							var key = attr.nodeName.replace(/^data-/, '');
							var value = attr.nodeValue;
							messages[key.toUpperCase()] = value;
						}
					}
				}
				return messages;
			}

			function chatButtonOnClick() {
				var $firstChat = $container.find('.chat:first'),
					$narrowContent = $firstChat.find('.narrow-content'),
					$h2 = $narrowContent.find('h2'),
					targetName = $firstChat.data('pushcall-id') || defaultPushcallId;

				var element = document.querySelector('#chat_labels');
				var chatMessages = validateLabel(element);

				$narrowContent.html('<div class="chat-container"></div>');
				$narrowContent.prepend($h2);

				$container.find('.chat-container').pcclient({
					targetName: targetName,
					clientType: 'chat',
					skin: '',
					locale: 'nl',
					forceHTML: true,
					userMessages: {
						nl: chatMessages
					},
					eventCallback: function (event) {
						if (event === 'closed') {
							//big hack to hide flash contact mail
							$narrowContent.find('.centerblock > p:not(.header):not(:first)').hide();
						}
					},
					context: this
				});
				event.preventDefault();
			}

			function initChat() {
				$container.find('.chat .button').on('click', chatButtonOnClick);
			}

			function init() {
				var $blockDirectActions = $currentButton.closest('.direct-actions'),
					targetName;

				$container = $('.call-me-now-container:eq(' + iterator + ')');
				containerId = 'call-me-now-container' + iterator;
				$container.attr('id', containerId);

				// 'hack' in case of direct actions
				if ($blockDirectActions.length) {
					$blockDirectActions.after($container);
				} else {
					$currentButton.parent().after($container);
				}

				//$container
				// if the chat container is the livechat container, disable resize action.
				if (!$container.hasClass('livechat')) {
					$window.on('resize', debounce(onResize, 100, { 'maxWait': 200 }));
				}
				$currentButton.on('click', toCallMeNowOnClick);


				var targetNameWhatsapp = $container.find('.whatsapp:first').data('pushcall-id') || defaultPushcallId;
				var whatsappContainer = $container.find('.whatsapp:first .narrow-content');
				var callMeContainer = $container.find('.call-me:first .narrow-content');

				if (whatsappContainer.length > 0) {
					var element = document.querySelector('#amn_labels');
					var amnMessages = validateLabel(element);

					whatsappContainer.html('').pcclient({
						targetName: targetNameWhatsapp,
						clientType: 'amn',
						skin: '',
						headerLevel: 2,
						locale: 'nl',
						forceHTML: true,
						userMessages: {
							nl: amnMessages
						},
						eventCallback: function (event, eventData) {
							$container.find('button.pcac_cmn_call').addClass('button').addClass('action');
						}
					});
				}

				var targetNameCallMeNow = $container.find('.call-me:first').data('pushcall-id') || defaultPushcallId;
				if (callMeContainer.length > 0) {
					var element = document.querySelector('#cmn_labels');
					var cmnMessages = validateLabel(element);

					var cmn_labels = $('#cmn_labels');
					callMeContainer.html('').pcclient({
						targetName: targetNameCallMeNow,
						clientType: 'cmn',
						skin: '',
						locale: 'nl',
						forceHTML: true,
						userMessages: {
							nl: cmnMessages
						}
					});
				}
				initChat();
			}

			init();
		});
	}

	toCallMeNow();

	window.toCallMeNow = toCallMeNow;

	/**
	 * Smart engage
	 */
	(function () {
		var minBrowserWidth = 660,
			$container = $('.smart-engage'),
			$prev = null,
			setMobileWidth = true;

		function isMobileWidth() {
			return $window.width() < minBrowserWidth;
		}

		function onClose() {
			$container.animate({
				bottom: -300
			},
				function () {
					$(this).hide();
				}
			);
		}

		function smartEngage() {
			var smartTimeout = ($('.smart-engage').data('smarttimeout') * 1000);
			if (!isMobileWidth()) { //desktop
				if (!setMobileWidth) {
					return;
				}
				setMobileWidth = false;
				$body.append($container);
				$container.addClass('fold-out');
				$container
					.css({ 'bottom': '-300px' })
					.hide()
					.delay(smartTimeout)
					.animate({
						bottom: 0
					}, {
						start: function () {
							$(this).show();
						},
						duration: 1000
					});
			} else { //mobile
				if (setMobileWidth) {
					//return;
				}
				$container.css({ 'bottom': '0' }).show();
				setMobileWidth = true;
				$container.insertAfter($prev);
				$container.removeClass('fold-out');
			}
		}

		function onResize() {
			if (!isMobileWidth()) { //desktop
				if (!setMobileWidth) {
					return;
				}
				setMobileWidth = false;
				$body.append($container);
				$container.addClass('fold-out');
				$container
					.css({ 'bottom': '-300px' })
					.hide()
					.delay(2000)
					.animate({
						bottom: 0
					}, {
						start: function () {
							$(this).show();
						},
						duration: 1000
					});
			}
			else { //mobile
				if (setMobileWidth) {
					return;
				}
				$container.css({ 'bottom': '0' }).show();
				setMobileWidth = true;
				$container.insertAfter($prev);
				$container.removeClass('fold-out');

			}

		}

		function init() {
			if (!$container.length) {
				return;
			}

			$container.append('<span class="close">X</span>');
			$container.find('span.close').on('click', onClose);
			$container.find('a.decline').on('click', onClose);

			$prev = $container.prev();
			//onResize();

			$window.on('onResize', debounce(smartEngage, 100, { 'maxWait': 200 }));

			var tcm = $('article.smart-engage').data('component');

			$.ajax({
				url: '/services/businessopen?tcm=' + tcm,
				success: function (data) {
					if (data == "true") {
						smartEngage();
					}
				}
			});
		}

		init();
	}());

	$('.calamity + app-root[data-lp-pages!=""]').prev()
		.addClass('calamity-location-picker');

	$('.calamity .close').click(function () {
		$(this).parent().remove();
	});

	/* call (tel numbers)  */
	(function () {
		var $links = $('.phone.option a.action');
		$links.each(function () {
			var link = $(this);
			link.magnificPopup({
				mainClass: 'lightbox-dialog lightbox-phonenumbers',
				//showCloseBtn: false,
				items: {
					type: 'inline',
					src: link.closest('.option').find('.phonenumbers')
				}
			});
		});
	}());

	/* Hashtag-page socialbox popup  */
	(function () {
		var $links = $('.social.option a.action');
		$links.each(function () {
			var link = $(this);
			link.magnificPopup({
				mainClass: 'lightbox-dialog lightbox-socialbox mfp-fade',
				//showCloseBtn: false,

				disableOn: function () {
					if ($(window).width() < 660) {
						return false;
					}
					return true;
				},
				removalDelay: 50, // was 1500
				items: {
					type: 'inline',
					src: link.closest('.option').find('.socialbox')
				}
			});
		});
	}());

	window.addPopupToJobAlertButton = function () {
		var
			button = $('.show-job-alert a'),
			content = button.parent().next('.job-alert');
		button.magnificPopup({
			mainClass: 'lightbox-dialog lightbox-socialbox mfp-fade lightbox-job-alert',
			removalDelay: 50, // was 1500
			items: {
				type: 'inline',
				src: content.remove()
			},
			callbacks: {
				open: function () {
					var
						newFilterHtml = '<span></span>';
					$('.used-filters a.remove-filter').each(
						function () {
							newFilterHtml +=
								'<span class="filter' +
								($(this).hasClass('clear-searchterm') ? ' search-filter' : '') +
								'">' +
								this.innerText +
								'</span>';
						}
					);
					content
						.find('.used-filters')
						.html(newFilterHtml)
						.removeClass('hidden');
				}
			}
		});
	}
	addPopupToJobAlertButton();

    /**
     * Animate elements in view when scrolling
     */
	(function () {
		var defaultOffset = 25,
			defaultAnimationQueueDelay = 500,
			$elements = $('.animate-in-view'),
			$animated = $elements.map(function () {
				var $element = $(this);

				return {
					queue: $element.data('animation-queue'),
					queueDelay: $element.data('animation-queue-delay') || defaultAnimationQueueDelay,
					$element: $element,
					animated: false,
					offsetTop: $element.offset().top + ($element.data('animation-offset') || defaultOffset)
				};
			}),
			animationQueues = {},
			debouncedHandler;

        /**
         * Initializes a new animation queue
         * @param {String} name
         * @param {Function} callback
         * @constructor
         */
		function AnimationQueue(name, callback) {
			this.name = name;
			this.animating = false;
			this.queue = [];
			this.callback = callback;
		}

        /**
         * String representation of the queue for debugging.
         * @returns {string}
         */
		AnimationQueue.prototype.toString = function () {
			return "AnimationQueue '" + this.name + "' (" + this.size() + ")";
		};
        /**
         * Returns the size of the queue
         * @returns {Number}
         */
		AnimationQueue.prototype.size = function () {
			return this.queue.length;
		};
        /**
         * Adds a animation to this queue
         * @param {Object} animation
         * @returns {AnimationQueue}
         */
		AnimationQueue.prototype.add = function (animation) {
			this.queue.push(animation);
			return this;
		};
        /**
         * Starts animating the queue if it's not animating yet.
         * @returns {AnimationQueue}
         */
		AnimationQueue.prototype.start = function () {
			return !this.animating ? this.animate() : this;
		};
        /**
         * Animates the next animation in the queue.
         * @returns {AnimationQueue}
         */
		AnimationQueue.prototype.animate = function () {
			var animation = this.queue.shift(),
				queue = this;

			if (animation) {
				this.animating = true;

				this.callback(animation);

				// We defer resuming the queue to the 'next tick', other animations might have been added to the queue.
				window.setTimeout(function () {
					if (queue.size()) {
						return queue.animate();
					}
					queue.animating = false;
				}, animation.queueDelay);
			}
			return this;
		};

        /**
         * Add the given animation to it's queue
         * @param {object} animation
         */
		function queueAnimation(animation) {
			var queue = animationQueues[animation.queue];
			if (!queue) {
				queue = animationQueues[animation.queue] = new AnimationQueue(animation.queue, triggerAnimation);
			}
			queue.add(animation).start();
		}

        /**
         * Handles the scroll event, checking for new elements within the viewport and triggering their animation
         */
		function scrollHandler() {
			var scrollBottom, $newInView;

			if (!$animated.length) {
				return;
			}

			scrollBottom = $window.scrollTop() + $window.height();
			$newInView = $animated.filter(function () {
				return !this.animated && this.offsetTop < scrollBottom;
			});

			$newInView.each(function () {
				// remove this element from the $animated array, it no longer needs to be checked
				$animated.splice($animated.index(this), 1);
				if (this.queue) {
					// queue this animation:
					queueAnimation(this);
				} else {
					// immedeately trigger the animation:
					triggerAnimation(this);
				}
			});
		}

        /**
         * Triggers the actual animation the animations element.
         * @param {Object} animation
         */
		function triggerAnimation(animation) {
			// We also trigger an event to be able to observe the animation from external sources
			animation.$element.addClass('in-view').trigger('in-view');
			animation.animated = true;
		}

		if ($elements.length) {
			debouncedHandler = debounce(scrollHandler, 50, {
				'leading': true,
				'trailing': false,
				'maxWait': 200
			});
			// observe scroll events
			$window.on('scroll', debouncedHandler);
			// start animating any already visible elements:
			debouncedHandler();
		}
	}());

    /**
     * Custom video's
     */
	(function ($videos) {
		$videos.each(function () {
			var video = videojs(this),
				$videoElement = $(this),
				$wrapper = $videoElement.closest('.cover-video'),
				classes = {
					'playing': 'video-playing',
					'paused': 'video-paused'
				},
				videoTitle = $videoElement.attr('title'),
				$playButton;

			classes.states = [classes.playing, classes.paused].join(' ');

			if ($wrapper.length) {
				// custom play button:
				if (videoTitle) {
					$playButton = $('<a>', {
						'href': '',
						'class': 'play-button',
						'text': $videoElement.attr('title')
					}).appendTo($wrapper);
				}

				// when the video is ready, start attaching event handlers
				video.ready(function () {
					video.on('play', function () {
						$wrapper.toggleClass(classes.states);
					});
					video.on('pause', function () {
						$wrapper.toggleClass(classes.states);
					});

					if ($playButton) {
						// observe our custom play button:
						video.on($playButton.get(0), 'click', function (event) {
							event.preventDefault();
							video.play();
						});
					}

					$wrapper
						.toggleClass(classes.playing, !video.paused())
						.toggleClass(classes.paused, video.paused());
				});
			}
		});
	}($('video')));

	// Open a video in lightbox
	// Use video-playlist to handle multiple videos
	(function ($videos) {
		$videos.each(function () {
			var $video = $(this),
				playButtonClass = 'play-button';

			// Attach lightbox handler to play button(contains iframe url)
			$video.find('.' + playButtonClass).magnificPopup({ type: 'iframe' });
		});
	}($('.video-mfp')));

	$('.column-layout script[data-video-id]').each(function () {
		var
			videoScript = $(this),
			id = videoScript.data('id'),
			addHandler = function () {
				var
					player = QuadiaPlayer.players[id];
				player.$on('play', function () {
					if (!$.magnificPopup.instance.isOpen) {
						var
							iframe = $('#' + id);
						$.magnificPopup.open({
							items: {
								src: iframe
							},
							mainClass: 'video-lightbox',
							callbacks: {
								open: function () {
									player.$on('playerReady', function () {
										if ($.magnificPopup.instance.isOpen) {
											setTimeout(function () {
												player.$emit('play');
											}, 100);
										}
									});
								},
								close: function () {
									videoScript.after(
										iframe
											.remove()
											.removeClass('mfp-hide')
									);
								}
							}
						});
					}
				})
			};
		if (window.QuadiaPlayer) {
			addHandler();
		} else {
			videoScript.on('load', addHandler);
		}
	});

	/* Custom video playlist, with this function we can create a playlist with a quadia player overlay */
	(function () {

		/* this is the container */
		$('.video-playlist').each(function () {

			var $container = $(this),
				$poster = $container.find('.cover-video'),
				$overlay = $container.find('.overlay-block');

			$container.find('.play-button').magnificPopup({ type: 'iframe' });

			/* list for video's in the playlist */
			$container.find('.list a').on('click', function (event) {
				var $item = $(this),
					data = $item.data();

				event.preventDefault();

				/* this fill the poster for the video */
				$poster.css('background-image', 'url(' + data.poster + ')');
				$poster.find('.play-button').attr('href', data.video);
				$poster.find('.play-button').text(data.buttontext);
				$overlay.find('.title').text(data.title);
				$overlay.find('.overlay-block-content').html(data.content);
				$overlay.find('.button').attr('href', data.callToActionUrl);

				$item.parents('ul').find('.is-active').removeClass('is-active');
				$item.addClass('is-active');
			});
		});
	})();

    /** We want collapsible-text closed when used on mobile,
     * we overwrite the settings with css to make sure the fields are always opend on other fields
     * **/
	(function () {

		var collapsible = true;

		function updateCollapsible() {

			if (collapsible) {
				if ($(window).width() <= 660) {
					$('.collapsible-text:gt(0)').find('.collapsible-toggle').not('.toggled').trigger('click');

					collapsible = false;
				}
			}
		}

		updateCollapsible();

		// Create a resize handler
		addResizeHandler(updateCollapsible);

	})();

	/**
	 * Load google maps data
	**/

	(function () {
		$('.maps').each(function () {
			var map = $('#map');

			proj4.defs('EPSG:28992', '+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.417,50.3319,465.552,-0.398957,0.343988,-1.8774,4.0725 +units=m +no_defs');
			var EPSG_28992 = new ol.proj.Projection({
				code: 'EPSG:28992',
				extent: [-285401.92, 22598.08, 595401.9199999999, 903401.9199999999],
				units: 'm'
			});
			ol.proj.addProjection(EPSG_28992);

			new ol.Map({
				target: 'map',
				layers: [
					new ol.layer.Tile({
						source: new ol.source.XYZ({
							projection: EPSG_28992,
							url: map.data('tiles')
						})
					}),
					new ol.layer.Vector({
						source: new ol.source.Vector({
							features: [
								new ol.Feature({
									type: 'marker',
									geometry: new ol.geom.Point(
										ol.proj.fromLonLat(
											[map.data('long'), map.data('lat')],
											EPSG_28992
										)
									)

								})
							]
						}),
						style: function () {
							return new ol.style.Style({
								image: new ol.style.Icon({
									anchor: [.5, 1],
									src: '/img/werken-bij/location-marker.png'
								})
							});
						}
					})
				],
				view: new ol.View({
					projection: EPSG_28992,
					center: ol.proj.fromLonLat(
						[map.data('long'), map.data('lat')],
						EPSG_28992
					),
					zoom: 10
				}),
				loadTilesWhileInteracting: true,
				loadTilesWhileAnimating: true,
				controls: [
					new ol.control.Zoom()
				]
			});
		});
	})();

	(function (splashPage) {
		var
			hiddenElements,
			HIDDEN_CLASS = 'hidden-for-splashpage',
			HIDDEN_SELF_CLASS = 'hidden-splashpage',
			COOKIE_NAME = 'show_splashpage',
			cookie = new Cookie(COOKIE_NAME);
		splashPage
			.each(function () {
				if (
					// Cookie reading does not seem to work
					document.cookie.split('; ')
						.some(function (cookie) {
							var
								name_value = cookie.split('='),
								name = name_value[0],
								value = name_value[1];
							return name == COOKIE_NAME && value == 'false';
						})
				) {
					splashPage
						.hide();
				} else {
					hiddenElements =
						$('main > *, #PostNL_globalNav_header')
							.not(splashPage)
							.addClass(HIDDEN_CLASS);
					splashPage
						.append(
							$('body > footer')
								.clone(true)
						);
				}
			})
			.find('.continue')
			.on('click', function (event) {
				document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
					detail: {
						name: "in_page_interaction",
						in_page: {
							"name": $(this).text(),
							"category": "link_click_button",
							"location": "body"
						}
					}
				})
				);
				cookie.write('false');
				hiddenElements
					.removeClass(HIDDEN_CLASS);
				splashPage
					.addClass(HIDDEN_SELF_CLASS);
				event.preventDefault();
			})
			.end()
			.find('.select-country')
			.on('click', function () {
				document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
					detail: {
						name: "in_page_interaction",
						in_page: {
							"name": $(this).text(),
							"category": "link_click_button",
							"location": "body"
						}
					}
				})
				);
			});
	})($('.splashpage'));

	$('.single-line-search form')
		.on('submit', function (event) {
			if (!$(this).find('input[type=search]').val()) {
				event.preventDefault();
			}
		})
		.find('input[type=search]')
		.on('invalid', function (event) {
			event.preventDefault();
		});

	$('.faq-menu-responsive select')
		.on('change', function () {
			document.location.href = this.value;
		});

	$(window).on('load', function () {
		var newHeight = 0;
		$('section.block > article.media-block').each(function (key, value) {
			var blockHeight = $(this).height();
			if (blockHeight > newHeight) {
				newHeight = blockHeight
			}
		});
		$('section.block > article.media-block').height(newHeight);
	});

	(function (carousel) {
		carousel.each(function () {
			var
				scrollTimer,
				scrollContainer = $(this).find('.scroll-container'),
				intersectionObserver = new IntersectionObserver(
					function (entries) {
						var
							carouselButtons = scrollContainer.next().find('.carousel-button');
						entries.forEach(function (entry) {
							$(carouselButtons[
								$(entry.target).prevAll().length
							])
								.toggleClass('active', entry.isIntersecting);
						});
					}, {
					root: scrollContainer[0],
					rootMargin: '0px',
					threshold: 1.0
				}
				);
			scrollContainer
				.after(
					$('<div class="carousel-buttons">')
						.append(
							scrollContainer.find('.equal-heights').map(function (index, panel) {
								intersectionObserver.observe(panel);
								return $('<a class="carousel-button">')
									.click(function () {
										panel.scrollIntoView({
											behavior: "smooth",
											block: "nearest",
											inline: "start"
										});
									});
							}).get()
						)
				)
				.scroll(
					function () {
						if (scrollTimer) {
							clearTimeout(scrollTimer);
						}
						scrollTimer = setTimeout(
							function () {
								// snap slide
								scrollContainer.next().find('.carousel-button.active').first()
									.click();
							},
							250
						);
					}
				)
				.addClass('initialized');
		});
	})($('.panels-wrapper.has-carousel'));

	(function (checkButton) {
		if (checkButton.length) {
			var
				form = checkButton.closest('form'),
				inputs = form.find('.personal-data .form-row input, .check-later .form-row input, .form-row select'),
				storedData = new Cookie('tempFormData'),
				goEdit = function () {
					form.removeClass('checking');
					inputs
						.show()
						.next('span.default.added')
						.remove()
						.closest('.form-row')
						.show();
				},
				goCheck = function () {
					var
						isValid = form.data().validator(form);
					if (isValid) {
						form.addClass('checking');
						inputs.each(function () {
							var
								input = $(this);
							if (input.val()) {
								input
									.hide()
									.after('<span class="default added">' + input.val() + '</span>');
							} else {
								input.closest('.form-row').hide();
							}
						});
					}
					return isValid;
				};

			if (storedData.value) {
				var
					storedNameValues = JSON.parse(
						decodeURIComponent(storedData.value)
					);
				form.find('.personal-data [name]').each(function () {
					var
						name = this.name;
					this.value = storedNameValues.find(function (nameValue) {
						return nameValue.name == name;
					})
						.value;
				});
			}

			window.addEventListener('hashchange', function () {
				if (document.location.hash === '#check') {
					if (!goCheck()) {
						// preventDefault
						window.history.back(-1);
					}
				} else {
					goEdit();
				}
			});

			if (document.location.hash === '#check') {
				goCheck();
			}

			form.find('.back').click(function (event) {
				// make sure enough time is left to store the cookie before navigating away
				event.preventDefault();
				storedData
					.write(
						JSON.stringify(
							form.serializeArray()
						)
					);
				document.location.href = this.href;
			});
		}
	})($('.pre-check-step .submit a'));

	if (window.userDetails) {
		$window
			.trigger('userDetails', window.userDetails);
	}
	$('#postalcodekillerapp').one('keyup', ':input:visible:first', function () {
		document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
			detail: {
				name: "funnel_interaction",
				funnel: {
					"name": "killer widget - postcode zoeken",
					"technology": "killerwidget",
					"type": "application",
					"step": "10",
					"step_name": "start killerwidget"
				}
			}
		})
		);
	});

	$('#postalcodekillerapp button').on('click', function () {
		var street = $('input[name=street]').val(),
			housenumber = $('input[name=number]').val(),
			addition = $('input[name=addition]').val(),
			city = $('input[name=city]').val();
		document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
			detail: {
				name: "funnel_interaction",
				funnel: {
					"name": "killer widget - postcode zoeken",
					"technology": "killerwidget",
					"type": "application",
					"step": "laatste",
					"step_name": "succes killerwidget"
				},
				optins: [
					{
						"category": "street",
						"answer": street
					},
					{
						"category": "housenumber",
						"answer": housenumber
					},
					{
						"category": "addition",
						"answer": addition
					},
					{
						"category": "city",
						"answer": city
					}
				]
			}
		})
		);
	});

	$('.recruitment-killer-app').one('keyup', ':input:visible:first', function () {
		document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
			detail: {
				name: "job_search_interaction",
				funnel: {
					"name": "killer widget - zoeken werkenbij",
					"technology": "killerwidget",
					"type": "application",
					"step": "10",
					"step_name": "start killerwidget"
				}
			}
		})
		);
	});

	$('.production-vacancies-killerapp button').on('click', function () {
		var
			radiusSelect = $('.production-vacancies-killerapp select#search-range'),
			radius = radiusSelect.find('option:selected').val(),
			postCode = $('.production-vacancies-killerapp input#vacancyLocation').val();

		document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
			detail: {
				name: "job_search_interaction",
				funnel: {
					"name": "killer widget - zoeken werkenbij",
					"technology": "killerwidget",
					"type": "application",
					"step": "laatste",
					"step_name": "succes killerwidget"
				},
				optins: [
					{
						"category": "postalcode",
						"answer": postCode
					},
					{
						"category": "radius",
						"answer": radius
					}
				]
			}
		})
		);
	});

	$('#zipcode-form fieldset').one('keyup', ':input:visible:first', function () {
		document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
			detail: {
				name: "job_search_interaction",
				funnel: {
					"name": "killer widget - zoeken werkenbij",
					"technology": "killerwidget",
					"type": "application",
					"step": "10",
					"step_name": "start killerwidget"
				}
			}
		})
		);
	});

	$('.office-vacancies-killerapp button').on('click', function () {
		var
			radiusSelect = $('.office-vacancies-killerapp select#search-range'),
			radius = radiusSelect.find('option:selected').val(),
			postCode = $('.office-vacancies-killerapp input#vacancyLocation').val(),
			searchTerm = $('.office-vacancies-killerapp input#vacancyName').val();

		document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
			detail: {
				name: "job_search_interaction",
				funnel: {
					"name": "killer widget - zoeken werkenbij",
					"technology": "killerwidget",
					"type": "application",
					"step": "laatste",
					"step_name": "succes killerwidget"
				},
				optins: [
					{
						"category": "postalcode",
						"answer": postCode
					},
					{
						"category": "search_term",
						"answer": searchTerm
					},
					{
						"category": "radius",
						"answer": radius
					}
				]
			}
		})
		);
	});

	$('body').on('click', ".vacancy-filters .filter-group input[data-datalayer]", function () {
		var vacancy = $(this).data('vacancyfilter'),
			filter = $(this).data('filteroption'),
			// Retrieve the current filters in datalayer. If the filters property doesn't exist, assign an empty array
			allFilters = (window.Intel && window.Intel.event && window.Intel.event.filters) ? window.Intel.event.filters : [],
			isFilterChecked = $(this).data('datalayer') === "productie" ? !filter.Selected : this.checked;
		if (isFilterChecked) {
			allFilters.push({
				name: vacancy.Title,
				value: filter.Name
			});
		} else {
			allFilters.forEach((currentFilter, index, object) => {
				if (currentFilter.name === vacancy.Title && currentFilter.value === filter.Name) {
					object.splice(index, 1);
				}
			});
		}

		document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
			detail: {
				name: 'filter_interaction',
				filter: {
					type: isFilterChecked ? "add filter" : "remove filter",
					interacted_filter_name: vacancy.Title,
					interacted_filter_value: filter.Name,
					nr_results: filter.Amount
				},
				filters: allFilters
			}
		})
		);
	});

	$('.killer-app.location-tool').one('keyup', ':input:visible:first', function () {
		document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
			detail: {
				name: "funnel_interaction",
				funnel: {
					"name": "killer widget - locatiewijzer",
					"technology": "killerwidget",
					"type": "application",
					"step": "10",
					"step_name": "start killerwidget"
				}
			}
		})
		);
	});

	/**	 
    * Add location form values to the url in a form the angular based location picker understands
    * For backward compatibility we still send the form fields in the query string
    */
	$('.location-tool form').on('submit', function (event) {
		var form = $(this),
			query = $('#address').val() || form.find('[name=geo-address]').val(),
			product = form.find('[name=productpanel]:checked'),
			location = $('input#address').val();
		event.preventDefault();

		document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
			detail: {
				name: "funnel_interaction",
				funnel: {
					"name": "killer widget - locatiewijzer",
					"technology": "killerwidget",
					"type": "application",
					"step": "laatste",
					"step_name": "succes killerwidget"
				},
				optins: [
					{
						"category": "location",
						"answer": location
					}
				]
			}
		})
		);
		document.location.href =
			this.action + '?' + form.serialize() + (query ? ('&address=' + query) : '') + '#/'
			+ (query ? query : '')
			+ (product.length ? '/' + product.val() : '');
	});

	// Personalizations
	$('body').on('click', "[data-personalizable] a", function () {
		var element = $(this).closest("[data-personalizable]");

		document.body.dispatchEvent(new CustomEvent('postnl-datalayer-event', {
			detail: {
				name: "personalisation_interaction",
				personalizations: [
					{
						"position": element.children("meta[itemprop='position']").attr("content"),
						"sub_position": element.children("meta[itemprop='sub_position']").attr("content"),
						"text": element.children("meta[itemprop='text']").attr("content"),
						"segment": element.children("meta[itemprop='segment']").attr("content")
					}
				]
			}
		}
		));
	});

	// Add the loaded class to be able to disable CSS animations until after the page load
	window.setTimeout(function () {
		$html.addClass('loaded');
	}, 0);
});

// Zorgt voor de functionaliteit van de samengestelde vacatures op de vacaturepaginas
(function handleCompoundedVacancies() {
	const compoundedVacanciesEl = Array.from(document.querySelectorAll('.compounded-vacancies'));

	if (compoundedVacanciesEl.length) {
		compoundedVacanciesEl.map(function (compoundedVac) {
			const visibleVacancies = 3;
			const singleVacancies = Array.from(compoundedVac.querySelectorAll('.single-vacancy'));

			if (singleVacancies.length > visibleVacancies) {
				setItemsVisibility(false);

				const showMoreBtnEl = document.createElement('a');
				showMoreBtnEl.classList.add('text-button')
				showMoreBtnEl.addEventListener('click', function (e) {
					e.preventDefault();
					setItemsVisibility(true);
				});
				showMoreBtnEl.textContent = 'Bekijk meer ' + (singleVacancies.length - 3);

				compoundedVac.appendChild(showMoreBtnEl);

				function setItemsVisibility(visibleState) {
					if (visibleState) {
						showMoreBtnEl.remove();
					}
					singleVacancies.map(function (vacancy, index) {
						if (index > 2) {
							visibleState ? vacancy.classList.remove('_hidden') : vacancy.classList.add('_hidden');
						}
					})
				}
			}
		})
	}

	$.get('/api/label/' + $('meta[name=publicationID]').attr('content') + '/browser-meldingen')
		.success(function (regEx_Notification) {
			$.each(regEx_Notification, function (regEx, notification) {
				if (navigator.userAgent.match(new RegExp(regEx)) !== null) {
					$('body > main').prepend(
						'<article class="narrow-content calamity block calamity-info"><div>'
						+ notification +
						'</div></article>'
					);
				}
			});
		});
})();

(function (ctaBar) {
	if (ctaBar.length) {
		if (
			ctaBar.is('main > *:last-child') ||
			ctaBar.is('main > .container > article > div > *:last-child')
		) {
			// make bar stick to footer
			$('body > footer').before(ctaBar);
		}
		var
			observing = ctaBar.next();
		(new IntersectionObserver(
			function (entries) {
				ctaBar.toggleClass(
					'stickied',
					!entries[0].isIntersecting
				);
			}, {
			rootMargin: observing.css('margin-top')
		}
		))
			.observe(observing[0]);
	}
})(
	$('.cta-bar')
);
linearGradientHomePageBanner();

// if title is not yet present, linearGradientHomePageBanner is called after renderHandlebars is called
function linearGradientHomePageBanner() {
	bannerTitleEl = document.querySelector('.hero-image .content .title p');
	if (bannerTitleEl) {
		gradientEl = document.querySelector('.hero-image.full-width .gradient');
		gradientEl.querySelector('.gradient__first').style.width = bannerTitleEl.getBoundingClientRect().right + 8 + 'px';
		gradientEl.querySelector('.gradient__last').style.width = document.querySelector('.hero-image.full-width .img').offsetWidth * 0.08 + 'px';
	}
};




/*jslint browser: true, plusplus: true, regexp: true, indent: 4, white:true */
/*global Modernizr, jQuery */

jQuery(function ($) {
	'use strict';

	var $window = $(window);

	// initialize qTip tooltips
	function initializeQTips(container) {
		var style = {
			tip: {
				width: 15,
				height: 10,
				mimic: 'center',
				offset: 15
			}
		};
		container = container || $(document.body);

		container.find('.tooltip, .tooltipped').each(function () {
			var element = $(this),
				target = element.data('tooltip');

			if (target) {
				element.find('> .icon').remove();
				// append a separate trigger
				element = $('<span>', {
					'class': 'icon',
					'text': 'i'
				}).appendTo(element);
			}

			element.qtip({
				// extract content from the element:
				content: target ? $(target) : element.html(),
				show: {
					// show on both mouse enter and click:
					event: 'mouseenter click',
					delay: 350, //necessary for Android
					
					// allow only one open qTip:
					solo: true
				},
				// allow the user to hover the tooltip:
				hide: {
					fixed: true,
					delay: 300
				},
				// reposition using the following viewport:
				position: {
					viewport: $window,
					my: 'bottom center',
					at: 'top center'
				},
				style: style
			});
		});
	}

	window.initializeQTips = initializeQTips;

	initializeQTips();
});

/*jslint browser: true, indent: 4, white:true */
/*global jQuery */

window.PostNL = window.PostNL || {};

window.PostNL.initSocialSharingButtons = function(cookieWidget) {
	var sharebuttons = jQuery('.social-media-sharing .medium');
	if(sharebuttons.length && !window.PostNL.initSocialSharingButtons.initialized) {
		if( window.hasCookiePermission && window.hasCookiePermission() || // 'old' style cookie permission
			cookieWidget && (
				cookieWidget.getPermissionInfo().allow ||
				cookieWidget.getPermissionInfo().hasPermission && 
				cookieWidget.getPermissionInfo().hasPermission('Cat.11')
			)
		) {
			
			window.PostNL.initSocialSharingButtons.initialized = true;
			sharebuttons.show();
		
			// Initialize Facebook
			(function (d, s, id) {
				'use strict';
				var js, fjs = d.getElementsByTagName(s)[0];
				if (d.getElementById(id)) {
					return;
				}
		        var
		            shareButton = jQuery('.fb-share-button'),
		            lang = (shareButton.length && shareButton.data('lang')) ? shareButton.data('lang') : 'nl_NL';
				js = d.createElement(s);
				js.id = id;
				js.src = "//connect.facebook.net/" + lang +  "/all.js#xfbml=1";
				fjs.parentNode.insertBefore(js, fjs);
			}(document, 'script', 'facebook-jssdk'));

			// Initialize Twitter
			(function (d, s, id) {
				'use strict';
				var js, fjs = d.getElementsByTagName(s)[0];
				if (d.getElementById(id)) {
					return;
				}
				if (!d.getElementById(id)) {
					js = d.createElement(s);
					js.id = id;
					js.src = '//platform.twitter.com/widgets.js';
					fjs.parentNode.insertBefore(js, fjs);
				}
			}(document, 'script', 'twitter-wjs'));

			// Initialize LinkedIn
			(function (d, s, id) {
				'use strict';
				var js, fjs = d.getElementsByTagName(s)[0];
				if (!d.getElementById(id)) {
					var langEl = d.querySelector('script[type="IN/Share"][data-lang]');
					js = d.createElement(s);
					js.id = id;
					js.src = '//platform.linkedin.com/in.js';
					js.text = 'lang: ' + (langEl ? langEl.dataset.lang : 'nl_NL');
					fjs.parentNode.insertBefore(js, fjs);
				}
			}(document, 'script', 'linkedin-js'));
		} else {
			sharebuttons.hide();
		}
		setShareLinks();
		function socialWindow(url) {
			var left = (screen.width - 570) / 2;
			var top = (screen.height - 570) / 2;
			var params = "menubar=no,toolbar=no,status=no,width=570,height=570,top=" + top + ",left=" + left;
			window.open(url,"NewWindow",params);
		}
		
		function setShareLinks() {
			var pageUrl = encodeURIComponent(document.URL);
			
			jQuery(".medium.facebook")
				.attr('href', 'https://www.facebook.com/sharer.php?u=' + pageUrl)
				.on("click", function(e) {
					e.preventDefault();
					url = "https://www.facebook.com/sharer.php?u=" + pageUrl;
					socialWindow(url);
				});
		
			jQuery(".medium.linkedin")
				.attr('href', 'https://www.linkedin.com/shareArticle?mini=true&url=' + pageUrl)
				.on("click", function(e) {
					e.preventDefault();
					url = "https://www.linkedin.com/shareArticle?mini=true&url=" + pageUrl;
					socialWindow(url);
				})
		}
	}
}

window.PostNL.initSocialSharingButtons(); // function is called later from cookie widget loading event as well	
/*!
 * accounting.js v0.4.2, copyright 2014 Open Exchange Rates, MIT license, http://openexchangerates.github.io/accounting.js
 */
(function(p,z){function q(a){return!!(""===a||a&&a.charCodeAt&&a.substr)}function m(a){return u?u(a):"[object Array]"===v.call(a)}function r(a){return"[object Object]"===v.call(a)}function s(a,b){var d,a=a||{},b=b||{};for(d in b)b.hasOwnProperty(d)&&null==a[d]&&(a[d]=b[d]);return a}function j(a,b,d){var c=[],e,h;if(!a)return c;if(w&&a.map===w)return a.map(b,d);for(e=0,h=a.length;e<h;e++)c[e]=b.call(d,a[e],e,a);return c}function n(a,b){a=Math.round(Math.abs(a));return isNaN(a)?b:a}function x(a){var b=c.settings.currency.format;"function"===typeof a&&(a=a());return q(a)&&a.match("%v")?{pos:a,neg:a.replace("-","").replace("%v","-%v"),zero:a}:!a||!a.pos||!a.pos.match("%v")?!q(b)?b:c.settings.currency.format={pos:b,neg:b.replace("%v","-%v"),zero:b}:a}var c={version:"0.4.1",settings:{currency:{symbol:"$",format:"%s%v",decimal:".",thousand:",",precision:2,grouping:3},number:{precision:0,grouping:3,thousand:",",decimal:"."}}},w=Array.prototype.map,u=Array.isArray,v=Object.prototype.toString,o=c.unformat=c.parse=function(a,b){if(m(a))return j(a,function(a){return o(a,b)});a=a||0;if("number"===typeof a)return a;var b=b||".",c=RegExp("[^0-9-"+b+"]",["g"]),c=parseFloat((""+a).replace(/\((.*)\)/,"-$1").replace(c,"").replace(b,"."));return!isNaN(c)?c:0},y=c.toFixed=function(a,b){var b=n(b,c.settings.number.precision),d=Math.pow(10,b);return(Math.round(c.unformat(a)*d)/d).toFixed(b)},t=c.formatNumber=c.format=function(a,b,d,i){if(m(a))return j(a,function(a){return t(a,b,d,i)});var a=o(a),e=s(r(b)?b:{precision:b,thousand:d,decimal:i},c.settings.number),h=n(e.precision),f=0>a?"-":"",g=parseInt(y(Math.abs(a||0),h),10)+"",l=3<g.length?g.length%3:0;return f+(l?g.substr(0,l)+e.thousand:"")+g.substr(l).replace(/(\d{3})(?=\d)/g,"$1"+e.thousand)+(h?e.decimal+y(Math.abs(a),h).split(".")[1]:"")},A=c.formatMoney=function(a,b,d,i,e,h){if(m(a))return j(a,function(a){return A(a,b,d,i,e,h)});var a=o(a),f=s(r(b)?b:{symbol:b,precision:d,thousand:i,decimal:e,format:h},c.settings.currency),g=x(f.format);return(0<a?g.pos:0>a?g.neg:g.zero).replace("%s",f.symbol).replace("%v",t(Math.abs(a),n(f.precision),f.thousand,f.decimal))};c.formatColumn=function(a,b,d,i,e,h){if(!a)return[];var f=s(r(b)?b:{symbol:b,precision:d,thousand:i,decimal:e,format:h},c.settings.currency),g=x(f.format),l=g.pos.indexOf("%s")<g.pos.indexOf("%v")?!0:!1,k=0,a=j(a,function(a){if(m(a))return c.formatColumn(a,f);a=o(a);a=(0<a?g.pos:0>a?g.neg:g.zero).replace("%s",f.symbol).replace("%v",t(Math.abs(a),n(f.precision),f.thousand,f.decimal));if(a.length>k)k=a.length;return a});return j(a,function(a){return q(a)&&a.length<k?l?a.replace(f.symbol,f.symbol+Array(k-a.length+1).join(" ")):Array(k-a.length+1).join(" ")+a:a})};if("undefined"!==typeof exports){if("undefined"!==typeof module&&module.exports)exports=module.exports=c;exports.accounting=c}else"function"===typeof define&&define.amd?define([],function(){return c}):(c.noConflict=function(a){return function(){p.accounting=a;c.noConflict=z;return c}}(p.accounting),p.accounting=c)})(this);

/*jslint browser: true, plusplus: true, regexp: true, indent: 4, white:true */
/*global Modernizr, jQuery, quadiaPlayer, accounting, feed */
jQuery(function ($) {
    "use strict";

    /**
     * Creates an alert pop up
     * @param {{title: String, subtitle: String, content: (*|jQuery|HTMLElement)}} content
     * @param {{containerElement: {}, titleElement: {}, subtitleElement: {}, contentElement: {}, buttonsElement: {}, buttons: {name: String}}} options Options object which allows the definition of sub element attributes and content. Objects are passed directly to the jQuery constructor.
     * @returns {{update: update, $element: (*|jQuery|HTMLElement), mfp: *}}
     * @todo Do we want to globalize this?
     */
    function alertPopUp(content, options) {
        var $container, $title, $subtitle, $content, $buttons, button;

        content = $.extend({}, {
            'title': '[no title]',
            'subtitle': null,
            'content': '[no-text]'
        }, content || {});

        options = $.extend(true, {
            'containerElement': {
                'class': 'lightbox-alert border-less block'
            },
            'titleElement': {
                'class': 'title'
            },
            'subtitleElement': {
                'class': 'subtitle'
            },
            'contentElement': {
                'class': 'popup-content'
            },
            'buttonsElement': {
                'class': 'buttons'
            },
            'buttons': {
                'close': 'Sluiten'
            }
        }, options || {});

        $container = $('<article>', options.containerElement);
        $title = $('<h2>', options.titleElement).appendTo($container);
        $subtitle = $('<p>', options.subtitleElement);
        $content = $('<div>', options.contentElement).appendTo($container);
        $buttons = $('<div>', options.buttonsElement).appendTo($container);

        $.each(options.buttons, function (name, value) {
            $('<button>', {
                'class': 'action button',
                'text': value
            }).appendTo($buttons).on('click', function (event) {
                event.preventDefault();
                $.magnificPopup.close();
            });
        });

        function update(content) {
            if (content.title) {
                $title.text(content.title);
            }
            if (content.hasOwnProperty('subtitle')) {
                if (content.subtitle) {
                    $subtitle.text(content.subtitle).insertAfter($title);
                } else {
                    $subtitle.remove();
                }
            }
            if (content.content) {
                $content.html(content.content);
            }
        }

        update(content);

        return {
            'update': update,
            '$element': $container,
            'mfp': $.magnificPopup.open({
                'items': {
                    'src': $container,
                    'closeBtnInside': false
                }
            })
        };
    }

    /**
     * This form gives us the option to add or remove channels,
     * the feed variable is set on a global level in is generated by incentro
     **/
    $('.price-form').each(function () {
        var $container = $(this),
            $channels = $container.find('.channels-form .channels'),
            $pricingContainer = $container.find('.pricing'),
            $pricing = $pricingContainer.find('.channels'),
            $price = $pricingContainer.find('.price .total span'),
            $reach = $pricingContainer.find('.price .reach span'),

            business = $container.find('input:radio[name=doelgroep][value=Zakelijk]').is(":checked");

            $container.find('input:radio[name=doelgroep]').on('change',function(){
                business = $container.find('input:radio[name=doelgroep][value=Zakelijk]').is(":checked");

                $pricing.find('.amount').trigger('change');
            });

        $channels.find('input').each(function(){
            var $this = $(this),
                $channel = $this.parents('.row'),
                $el, data;


            /* find channel data in json */
            $.each(feed.Pricings, function (i, v) {
                if(feed.Pricings[i].Id == $this.val()){
                    data = feed.Pricings[i].Rate;

                    return false;
                }
            });

            if(data){

            $this.on('change', function(){
                var price;
                /*
                * When a element is checked we add it to the list with the other channels
                * */
                if($this.is(':checked')) {

                    $el = $('<div class="channel"><a href="#" class="delete">Verwijderen</a>' +
                        '<p class="channel-title">' + $channel.find('.description').text() + '</p>' +
                        '</div>');

                    /*
                     * fixed only has a price witch can't be changed.
                     * */

                    if (data.PriceType === 'Fixed') {

                        price = getElementPrice(data, business, false);

                        $el.append('<div class="form-row text"><input type="hidden" name="' + $this.val() + '" class="amount" value="' + data.Rates[0].Amount + '" ><label class="label">Prijs</label> <span class="field"><input type="number" class="input price" value="' + price.price + '" readonly></span></div>');
                    }

                    if (data.PriceType === 'Flexible' || data.PriceType === 'Sliding-scale') {
                        /*
                         * the normal version allows for a price and amount, sliding scale generates a select field
                         * */
                        if (data.PriceType === 'Flexible') {

                            $el.append(
                                '<div class="form-row text"><label class="label">Bereik</label> <span class="field"><input type="number" name="' + $this.val() + '" class="input amount" min="' + data.Rates[0].Amount + '" value="' + data.Rates[0].Amount + '" ></span></div>' +
                                '<div class="form-row text"><label class="label">Prijs</label> <span class="field"><input type="number" step="0.01" class="input price" value="" ></span></div>'
                            );
                        } else {

                            var $options = $('<select class="input amount" name="' + $this.val() + '"></select>');

                            $.each(data.Rates, function (i) {
                                $options.append('<option value="' + data.Rates[i].Amount + '">' + data.Rates[i].Amount + '</option>');
                            });

                            $el.append(
                                '<div class="form-row select"><label class="label">Bereik</label> <span class="field">' + $options[0].outerHTML + '</span></div>' +
                                '<div class="form-row text"><label class="label">Prijs</label> <span class="field"><input type="number" step="0.01" class="input price" value="" readonly></span></div>'
                            );
                        }
                    }
                        /**
                         *  When the channel has a checkbox available add that to the list of options
                         */
                        if (data.ChannelOptions && accounting.toFixed(data.ChannelOptions.ItemPrice, 2) > 0) {


                            var id = Math.floor((Math.random() * 1000) + 1);
                            var channelOption = '<div class="form-row single checkboxes"><span class="field">';
                            var dataChannelChecked = String(data.ChannelOptions.Checked);

                            if (dataChannelChecked.toLowerCase() != 'true') {
                                channelOption += '<input class="input check" type="checkbox" name="" id="field-' + id + '" value="1">';
                            } else {
                                channelOption += '<input class="input check" type="checkbox" name="" id="field-' + id + '" value="1" checked="True">';
                            }
                            channelOption += '<label class="label" for="field-' + id + '">' + data.ChannelOptions.Description + '</label></span></div>';

                            $el.append(channelOption);
                        }

                        var $amount = $el.find('.amount'),
                            $price = $el.find('.price'),
                            $check = $el.find('.check');

                        /*
                         * Price and amount have a relation with each other so we need to change both.
                         */

                        price = getElementPrice(data, business, $check.is(':checked'));

                        $check.on('change', function () {
                            $amount.trigger('change');
                        });

                        $amount.on('change', function () {

                            price = getElementPrice(data, business, $check.is(":checked"), $(this).val());

                            $amount.val(price.amount);
                            $price.val(price.price);

                            $pricing.trigger('recalculate');

                        }).trigger('change');

                        $price.on('change', function () {

                            price = getElementPrice(data, business, $check.is(":checked"), 0, $(this).val());

                            $amount.val(price.amount);
                            $price.val(price.price);

                            $pricing.trigger('recalculate');
                        });


                        /**
                         * When a user  removes ( or unchecks) the element remove it.
                         */
                        $el.find('.delete').on('click', function (event) {
                            event.preventDefault();
                            $el.remove();
                            $this.attr('checked', false).trigger('change');
                        });

                        $pricing.append($el);

                        $('select.input').selectBoxIt();

                        $pricing.trigger('recalculate');

                        // check for up-selling

                        if ($channel.data('up-selling')) {
                            $container.find('.' + $channel.data('up-selling')).show();
                        }

                } else {
                    if ($el) {
                        $el.remove();
                    }
                    /*
                     * We have some up selling options ( when the data element is set show the class )
                     * */

                    if ($channel.data('up-selling')) {
                        $container.find('.' + $channel.data('up-selling')).hide();
                    }

                    $pricing.trigger('recalculate');
                }

                $channel.toggleClass('is-active', $this.is(':checked'));


            }).trigger('change');
            } else{
                $channel.hide();
            }
        });

        $pricing.on('recalculate',function(){

            var totalPrice = 0;
            var totalReach = 0;

            $pricing.find('.price').each(function(){
                totalPrice += Number($(this).val());
            });

            $pricing.find('.amount').each(function(){
                if (Number($(this).val()) > 1) {
                    totalReach += Number($(this).val());
                }
            });

            if(totalReach <= 0){
                $reach.parent().hide();
                $reach.parent().prev().hide();
            }else{
                $reach.parent().show();
                $reach.parent().prev().show();
            }

            $price.text(accounting.formatNumber(totalPrice, 2, ".", ","));
            $reach.text(totalReach);
            $pricingContainer.toggleClass('no-channels',totalPrice == 0);
        });

        $('.price-form .first-step-form').on('submit',function(event){

            event.preventDefault();

            var $popupForm = $('#request-quote'),
                channels = [];

            $('.pricing-form .channels .channel').each(function(){
                var $channel = $(this);

                $channel.find('.amount').each(function(){
                    var $input = $(this);

                    if($input.is('input') || $input.is('select')){
                        channels.push({"id": $input.attr('name'), "Amount" : $input.val(), "Checked": $channel.find('.checkboxes input').is(':checked') });
                    }
                });
            });

            $popupForm.find('input[name="channel"]').val(JSON.stringify(channels));
            $popupForm.find('input[name="target"]').val($('.channels-form input[name="doelgroep"]:checked').val());

            $popupForm.one('submit',function(event){
                var $form = $(this);

                event.preventDefault();

                $.ajax({
                    type: "POST",
                    url: $form.attr("action"),
                    data: $form.serialize(),
                    success: function () {
                        var data = $form.data();

                        $.magnificPopup.close();

                        alertPopUp({
                            'title': data.alertTitle,
                            'subtitle': data.alertSubtitle,
                            'content': $('<p>', {
                                'html': data.alertText
                            })
                        });
                    }
                });
            });

             // open a popup with a new form
            $.magnificPopup.open({
                items: {
                    src: $popupForm
                },
                type: 'inline',
                preloader: false,
                focus: '#name',

                // When element is focused, some mobile browsers in some cases zoom in
                // It looks not nice, so we disable it:
                callbacks: {
                    beforeOpen: function() {
                        if($(window).width() < 700) {
                            this.st.focus = false;
                        } else {
                            this.st.focus = '#name';
                        }
                    }
                }
            });

            $popupForm.find('.cancel').on('click', function(event){ event.preventDefault(); $.magnificPopup.close();});
        });

        $container.find('.trigger-popup').each(function(){

              $(this).magnificPopup({
                type: 'inline',
                preloader: false,
                focus: '#name',

                // When element is focused, some mobile browsers in some cases zoom in
                // It looks not nice, so we disable it:
                callbacks: {
                    beforeOpen: function() {
                        if($(window).width() < 700) {
                            this.st.focus = false;
                        } else {
                            this.st.focus = '#name';
                        }
                    }
                }
            });

            $(this.getAttribute('href')).find('.cancel').on('click', function(event){ event.preventDefault(); $.magnificPopup.close();});
        });

        // we want the channel form to move up ( desktop and up )
        if($(window).width() >= 1001) {

            var $form = $container.find('.channels-form'),
                offset = $form.find('fieldset').first().position();

           $form.css('margin-top', - (80 + offset.top ));

        }

    });

    $('#popup-form').on('submit', function (event) {
        var $form = $(this);

        event.preventDefault();

        $.ajax({
            type: "POST",
            url: $form.attr("action"),
            data: $form.serialize(),
            success: function () {

                var data = $form.data();

                //empty the form
                $form[0].reset();

                // close the popup
                $.magnificPopup.close();


                // show the thank you popup
                alertPopUp({
                    'title': data.alertTitle,
                    'subtitle': data.alertSubtitle,
                    'content': $('<p>', {
                        'html': data.alertText
                    })
                });
            }
        });
    });

/* helper functions */


function getElementPrice(data, isBusiness, isChecked, amount, price){

    var row = {
        min_amount: 0,
        min_price: 0,
        price:0,
        amount: 0
    }

    amount = typeof amount !== 'undefined' ? parseInt(amount) : 0;
    price = typeof price !== 'undefined' ? price : 0;

    var business = 0,
        add = 0;

    if(isBusiness){
        business = data.Rates[0].Business;
    }

    if(data.ChannelOptions && accounting.toFixed(data.ChannelOptions.ItemPrice, 2) > 0){
        add = data.ChannelOptions.ItemPrice;

        if(isChecked){
            add = data.ChannelOptions.PriceChecked;

            if(add < 0 || data.ChannelOptions.PriceChecked == 0){add = 0};
        }

        if(isBusiness){
            add  = data.ChannelOptions.ItemPrice + data.ChannelOptions.Difference;

            if(isChecked){
                add = data.ChannelOptions.PriceChecked + data.ChannelOptions.Difference;
                if(add < 0 || data.ChannelOptions.PriceChecked == 0){add = 0};
            }
        }
    }

    row.min_amount = data.Rates[0].Amount;
    row.min_price  = accounting.toFixed(data.Rates[0].Amount * (data.Rates[0].Price + business + add) + data.Rates[0].FixedPrice, 2);

    if(amount > 0){

        row.amount = amount;

        $.each(data.Rates, function (i, rate) {

            if(row.amount >= rate.Amount){

                if(isBusiness){
                    row.price  = accounting.toFixed(amount * (rate.Price + rate.Business + add) + rate.FixedPrice, 2);
                }else{
                    row.price  = accounting.toFixed(amount * (rate.Price + add) + rate.FixedPrice, 2);
                }


            }else{
                return false;
            }
        });
    }

    if(price > 0){

        row.price = accounting.toFixed(price,2);
        var fixed = data.Rates[0].FixedPrice;

        $.each(data.Rates, function(i) {

            var rulePrice = data.Rates[i].Price + business + add;

            fixed = data.Rates[i].FixedPrice;

            if(row.price - fixed >= (data.Rates[i].Amount * rulePrice)){
                price = rulePrice;
            }else{
                return false;
            }
        });

        row.amount = (Math.floor((row.price - fixed) / price));
    }

    if(accounting.unformat(row.price) < accounting.unformat(row.min_price)){
        row.price = row.min_price;
    }

    if(row.amount < row.min_amount){
        row.amount = row.min_amount;
    }

    return row;
    }
});

// JavaScript Document

var PNLNav = PNLNav || {};
PNLNav.Site = {
	busy: false,

	// Resize
	desktopSize: 1151,
	tabletSize: 1001,
	mobileSize: 767,
	mobilePortraitSize: 481,
	resizeThrottle: undefined,
	activeMenuItem: undefined,
	currentWidth: undefined,

	init: function() {
		setTimeout(function() {
			PNLNav.Site.currentWidth = $(window).width();

			PNLNav.Site.fixedHeader();
			PNLNav.Site.toggleMobileMenu(); // TODO: this should be triggered from the account-widget.js
			PNLNav.Site.toggleMenuCategories();
			PNLNav.Site.searchFocus();
			PNLNav.Site.initShopcart();
			PNLNav.Site.largeMenuTouch();
			PNLNav.Site.largeLanguageTouch();
			PNLNav.Site.toggleMobileFooterMenu();

			// resize
			$(window).resize(PNLNav.Site.docResize);

			// scroll
			$(window).scroll(PNLNav.Site.docScroll);

		}, 10);
	},

	docResize: function() {
		// on resize several checks are done. This is done with a throttle, so that the events don't flood the browser
		PNLNav.Site.resizeThrottle = setTimeout(function() {
			PNLNav.Site.currentWidth = $(window).width(); // update current width
			PNLNav.Site.closeMobileMenus();	// Close/Reset the menu, when switched from small to large viewport
			PNLNav.Site.largeMenuTouch(); // listen for touch-events in menu on large viewports
			PNLNav.Site.largeLanguageTouch(); // listen for touch-events in language picker on large viewports
			PNLNav.Site.closeShopcartTooltip(); //
		}, 500);
	},

	closeShopcartTooltip: function() {
		clearTimeout(PNLNav.Site.resizeThrottle);
		var shopcartIcon = $('.shopcart-icon');
		if (($(window).width() < PNLNav.Site.tabletSize)) {
			shopcartIcon.removeClass('open');
		};
	},

	largeMenuTouch: function() {
		clearTimeout(PNLNav.Site.resizeThrottle);
		var navItems = $('nav > ul > li:not(.home)');
		navItems.on('touchstart', function ($event) {
			if (PNLNav.Site.currentWidth > PNLNav.Site.tabletSize) {
				var hasSubmenu = $(this).find('ul').length > 0;

				// If submenu should be opened
				if (!$(this).hasClass('hover') && hasSubmenu){
					$event.preventDefault();
					$event.stopPropagation();
					navItems.removeClass('hover');
					$(this).addClass('hover');

					// event listener on body for closing the menu
					$('body').on('touchend', PNLNav.Site.largeMenuCloseMenu);
				}

				// "else" follow link
			}
		});
	},

	largeMenuCloseMenu: function() {
		var navItems = $('nav > ul > li:not(.home)');
		// if touch target is not in the <nav> element
		if (!$(event.target).parents('nav').length > 0 ) {
			navItems.removeClass('hover');
			// remove body event listener, to prevent flooding of eventlisteners
			$('body').off('touchend', PNLNav.Site.largeMenuCloseMenu)
		}
	},

	largeLanguageTouch: function() {
		clearTimeout(PNLNav.Site.resizeThrottle);

        var languageOptions = $('.language-options').find('ul');
		var languageOptionsActive = $('.language-options').find('ul li.active a');

        languageOptionsActive.unbind()
        languageOptions.unbind()

        languageOptionsActive.on('click', function($event) {
            // if picker is not open yet, open it
            if (!$('.language-options ul').hasClass('hover')) {
                $event.preventDefault();
                $event.stopPropagation();
                $('.language-options ul').addClass('hover');


            } else {
                $('.language-options ul').removeClass('hover');
                $event.preventDefault();
                $event.stopPropagation();
            }

        })

        languageOptions.on('click', function($event) {
            // if picker is not open yet, open it
            if ($('.language-options ul').hasClass('hover')) {
                $('.language-options ul').removeClass('hover');
            }
        })
	},

	largeLanguageTouchClose: function() {
		var languageOptions = $('.language-options').find('ul');
		// if touch target is not in the .language-options element
		if (!$(event.target).parents('.language-options').length > 0 ) {
			languageOptions.removeClass('hover');
			// remove body event listener, to prevent flooding of eventlisteners
			$('body').off('touchend', PNLNav.Site.largeLanguageTouchClose);
		}
	},


	closeMobileMenus: function() {
		clearTimeout(PNLNav.Site.resizeThrottle);
		var header = $('#PostNL_globalNav #PostNL_globalNav_header');
		var navButton = header.find('.mobile-nav');

		// simulate 'close' click if window resize results in small viewport to large viewport AND one of the menu's
		// is open.

		if (($(window).width() > PNLNav.Site.tabletSize) && (header.hasClass('show-menu-left'))) {
			navButton.click();
		}

	},

	docScroll: function() {
	},

	fixedHeader: function() {

		var header = $('#PostNL_globalNav_header');
		var lastScrollTop = 0;

		function setHeader() {
			var windowHeight = $(window).height();
			var siteHeight = $('body').outerHeight();
			var scrollMargin = (siteHeight - windowHeight);
			var scrollTop = $(document).scrollTop();
			if (scrollTop > lastScrollTop){
				if (scrollTop > 50) {
					header.addClass('removed');
				}
			}
			else {
				if (scrollTop < scrollMargin) {
					header.removeClass('removed');
				}
			}
			header.toggleClass('PostNL_globalnav_added', scrollTop > 125);

			lastScrollTop = scrollTop;
		}

		$('body').scroll(function(){
			setHeader();
		});

		$(window).scroll(function(){
			setHeader();
		});

		var windowHeight = $(window).height();
		var siteHeight = $('.site').outerHeight();

		if (siteHeight <= windowHeight) {
			header.removeClass('removed');
		}
	},

	toggleMobileMenu: function() {
		var header = $('#PostNL_globalNav #PostNL_globalNav_header');
		var navButton = header.find('.mobile-nav');
		var body = $('body');
		var scrollPos;


		navButton.click(function() {
			if(!header.hasClass('show-menu-left')) {
				header.addClass('show-menu-left');
				scrollPos = $(window).scrollTop();
				body.addClass('menu-open');
				PNLNav.Site.activeMenuItem = header.find('nav').find('.active');
			}
			else {
				header.removeClass('show-menu-left');
				header.find('nav').find('.active').removeClass('active');
				body.removeClass('menu-open');
				window.scrollTo(0, scrollPos);
				PNLNav.Site.activeMenuItem.addClass('active');
			}

			if(header.hasClass('show-menu-right')) {
				header.removeClass('show-menu-right');
			}
		});
	},

	toggleMenuCategories: function() {
		$('#PostNL_globalNav_header').find('li').click(function(e) {
			var target = $(e.target);
			if(($(window).width() < PNLNav.Site.tabletSize) && (!target.is('a') && !target.parents().is('.quicklinks'))) {
				if($(this).find('a').next().is('div')) {
					// alert('parent');
					var thisLi = $(this);
					var otherLi = thisLi.siblings('li');

					if(!thisLi.hasClass('active')) {
						thisLi.addClass('active');
						otherLi.removeClass('active');
						otherLi.find('li').removeClass('active');
					}
					else {
						thisLi.removeClass('active');
						thisLi.find('li').removeClass('active');
					}
					e.preventDefault();
					e.stopPropagation();
				}
			}
		});
	},

	searchFocus: function() {
		var navMenu = $('#PostNL_globalNav_header').find('.navigation-menu');
		var navSearch = $('#PostNL_globalNav_header').find('.navigation-search');
		var navSearchInput = $('#PostNL_globalNav_header').find('.navigation-search input[type="search"]');
		var searchForm = $('#PostNL_globalNav_header').find('#search-form');

		navSearch.hover(function() {
				navMenu.addClass('search-hover');
			},
			function() {
				navMenu.removeClass('search-hover');
			});

		navSearchInput.focus(function() {
			navMenu.addClass('search-focus');
		});

		navSearchInput.blur(function() {
			// small timeout so the blur isn't invoked immediately when the use presses the 'submit' button
			var blurInput = setTimeout((function(){
				navMenu.removeClass('search-focus');
			}), 100);
		});

		searchForm.submit(function() {
			if (!navSearchInput.val()) {
				return false;
			}
		});
	},
	
	initShopcart: function() {
		var header = $('#PostNL_globalNav_header');
		var shopCart = header.find('.carts');
		if(!shopCart.length) {
			header.addClass('no-carts');
		}
	},

	toggleMobileFooterMenu: function() {
		var
			computedstyle,
			ACTIVE_CLASS = 'active';
			triggers = $('#PostNL_globalNav_footer_variable, #PostNL_globalNav_footer_fixed')
				.find('[data-role=trigger]'),
			lis = triggers.closest('li');

		triggers.on('click', function() {
			var
				triggerLi = $(this).closest('li'),
				ul = triggerLi.find('ul');
			lis.not(triggerLi)
				.removeClass(ACTIVE_CLASS)
				.find('ul').attr('style', null);
			if(triggerLi.hasClass(ACTIVE_CLASS)) {
				ul.attr('style', null);
			} else {
				computedstyle = getComputedStyle(ul[0]);
				ul.height(
					ul[0].scrollHeight -
					computedstyle.paddingTop.split('px')[0] -
					computedstyle.paddingBottom.split('px')[0]
				);
			}
			triggerLi.toggleClass(ACTIVE_CLASS);
		});
	}
};

$(document).ready(PNLNav.Site.init);

(function ($) {

    $.fn.delayKeyup = function (callback, ms) {
        var timer = 0;
        $(this).keyup(function () {
            clearTimeout(timer);
            timer = setTimeout(callback, ms);
        });
        return $(this);
    };

    $.fn.autoSuggest = function () {
        var defaults = {
            input: "",
            data: [],
            clicked: false
        },
            settings = $.extend({}, defaults),

            showSearch = function (that) {
                $(that).find('.suggestion-results').show();
            },

            resetSearch = function (that) {
                $(that).find('.suggestion-results').hide();
                $(that).find('.gsa-suggestions').html('');
                $(that).find('.suggestions').html('');
            },

            // Get all autosuaggest data.
            getData = function (that) {
                $.ajax({
                    type: 'GET',
                    url: '/api/Autosuggestion/' + $(that).data('publication'),
                    dataType: 'json',
                    success: function (response) {
                        settings.data = response;
                    }
                });
            },

            gsaAutoComplete = function (that) {
                var $input = $(that).find('input.autocomplete');
                var currentLanguage = $('body').find('.current-language').data('language');
                var count = 0;
                $.ajax({
                    type: 'GET',
                    url: currentLanguage + '/search/suggest?q=' + $input.val(),
                    dataType: 'json',
                    success: function (response) {
                        response = typeof response === 'string' ? $.parseJSON(response) : response;
                        if (response != null) {
                            var list = $('<ul />');
                            var re = new RegExp($input.val(), "g");
                            $.each(response, function (index, suggestion) {
                                count++;
                                var text = suggestion.replace(re, '<strong>' + $input.val() + '</strong>');
                                var suggest = $('<li />').append(
                                    $('<a />', {
                                        'href': currentLanguage + '/search?q=' + suggestion + '&searchEntry=auto-suggest',
                                        'class': 'gsa-suggest-link',
                                        'html': text
                                    })
                                );
                                list.append(suggest);
                            });
                            $(that).find('.gsa-suggestions').html(list);
                        }

                        $('.gsa-suggestions ul li').on('click', function () {

                            var url = $(this).find('a').attr('href');
                            window.location.href = url;
                        });
                        // show results
                        if (count > 0) {
                            showSearch(that);
                        } else {
                            resetSearch(that);
                        }
                        getMatches(that);
                    }
                });
            },

            getMatches = function (that) {
                var $input = $(that).find('input.autocomplete');
                var suggestData = [];
                $.each(settings.data, function (index, suggestion) {
                    var matched = false;
                    $.each(suggestion.matches, function (index, match) {
                        if (match.indexOf($input.val()) > -1) {
                            matched = true;
                        }
                    });
                    if (matched && $input.val().length > 2) {
                        suggestData.push({
                            type: 'tridion',
                            'data': {
                                title: suggestion.title,
                                description: suggestion.description,
                                image: suggestion.image,
                                button: suggestion.button
                            }
                        });
                    }
                });

                if (suggestData.length > 0) {
                    renderTridionData(that, suggestData);
                    $(that).find('.suggestions').show();
                    showSearch(that);
                } else {
                    $(that).find('.suggestions').hide();
                }
            },

            renderTridionData = function (that, suggestData) {
                var suggestions = [];
                if (suggestData.length > 0) {
                    $.each(suggestData, function (index, suggestion) {
                        // Create suggest
                        var suggest = ('<a href="' + suggestion.data.button.Url + '" target="' + suggestion.data.button.Target + '" class="suggestion">' +
                            '<div class="image-block" style="background-image: url(' + suggestion.data.image.Url + ')"></div>' +
                            '<div class="content">' +
                            '<h2 class="title">' + suggestion.data.title + '</h2>' +
                            '<div class="description">' + suggestion.data.description + '</div>' +
                            '</div>' +
                            '</a>');


                        suggestions.push(suggest);
                    });
                    $(that).find('.suggestions').html(suggestions);
                }
            }

        return this.each(function () {
            var that = this;
            var $input = $(that).find('input.autocomplete');

            // Get autosuggest data if data is zero.
            $input.on('click', function () {
                if (settings.data.length == 0) {
                    getData(that);
                }
            });

            // Start with GSA auto suggests.
            $input.delayKeyup(function () {
                if ($input.val().length > 0) {
                    gsaAutoComplete(that);
                } else {
                    resetSearch(that);
                }
            }, 300);

            $('.suggestions').on('click', function () {
                settings.clicked = true;
            }),
            // If input field focus show results or reset results.
            $(window).on('click', function () {
                if ($input.is(':focus')) {
                    if ($input.val().length > 0) {
                        gsaAutoComplete(that);
                    }
                } else {
                    if (!settings.clicked) {
                        resetSearch(that);
                    }
                    settings.clicked = false;
                }
            });
            $('ol#main-menu li').hover(function () {
                if ($(this).find('a').hasClass('has-children')) {
                    $(that).find('.suggestion-results').hide();
                }
            }, function () {
                if ($input.is(':focus')) {
                    if ($input.val().length > 0) {
                        $(that).find('.suggestion-results').show();
                    }
                }
            });

        });
    };

    PNLNav.GSA = {
        init: function () {
            // Only start if object is available
            // This makes it possible to initialize without objects present. In
            // combination with Angular the object will not be available on
            // ready. Angular will make a second call to initializiation when
            // decided it's ready.
            if ($('form.new-header-search').length > 0) {

                $('.new-header-search').on('submit', function () {
                    if ($(this).find('input.gsa-autocomplete').val() == '') {
                        return false;
                    }
                });

                $('form.new-header-search').autoSuggest();
            }
        }
    };
}(jQuery));

$(document).ready(PNLNav.GSA.init);

$(function () {
    $('div.external-form:not(.win-campaign)').find('form').on('submit', function () {
       $(this).find('span.submit').addClass('loading');
    });
    $('form.popup-form').on('submit', function () {
        $(this).find('button[type=submit]').addClass('loading');
    });
});
var ECOM = ECOM || {};
ECOM.Site = {
    cookieName: 'customerCartId',
    endPoint: undefined,
    customerCartId: null,
    shopcartIcon: $('.shopcart-icon'),
    busyButton: undefined, // Holds active add-to-cart button
    loadingClass: 'loading',
    doneClass: 'added',
    errorClass: 'error',

    init: function() {
        setTimeout(function() {
            ECOM.Site.bindButtons();
        }, 10);
    },

    // listen for click event on 'add' button
    bindButtons: function() {
        $('.add-to-cart').on('click', function() {
          // We only allow on click at a time
            if (!ECOM.Site.busyButton) {
                // console.log('click()', this);

                var productID = $(this).data('productId');
                var amount = $(this).data('cartAmount');
                ECOM.Site.busyButton = $(this);
                ECOM.Site.busyButton.addClass(ECOM.Site.loadingClass);

                ECOM.Site.endPoint = $(this).data('apiUrl') + 'carts/';

                ECOM.Site.addToCart(productID, amount);
            } else {
                //console.log('click() ignored');
            }

        });
    },

    // Check if cookie with cartID exists, if it exists, check that it is still valid
    // if it is valid add the product to the existing cart
    // If not, create a new cart
    addToCart: function(productID, amount) {
        if (ECOM.Site.busyButton) {
            if (ECOM.Site.checkCookie()) {
                $.get(ECOM.Site.endPoint + ECOM.Site.customerCartId)
                    .done(function(result) {
                        if(result.id) {
                            ECOM.Site.addToExistingCart(productID, amount);
                        } else {
                            ECOM.Site.createNewCart(productID, amount);
                        }
                    })
                    .error(function() {
                        ECOM.Site.createNewCart(productID, amount);
                    });
            } else {
                ECOM.Site.createNewCart(productID, amount);
            }
        } else {
            // console.log('addToCart() ignored');
        }
    },

    // checkCookie sets the ECOM.Site.customerCartId variable with the existing cookie and returns true
    // OR it returns false
    checkCookie: function() {
        var value = "; " + document.cookie;
        var parts = value.split("; " + ECOM.Site.cookieName + "=");

        if (parts.length == 2) {
            ECOM.Site.customerCartId = JSON.parse(parts.pop().split(";").shift());
            return true;
        } else {
            return false;
        }
    },

    // set the cookie with the cartID as input
    // This function is called from the createNewCart function
    setCookie: function(cartID) {
        var lifeTime = 7; //7 days
        var date = new Date();
        date.setTime(date.getTime() + (lifeTime * 24 * 60 * 60 * 1000));
        var expires = "; expires=" + date.toGMTString();

        ECOM.Site.customerCartId = cartID;
        document.cookie = ECOM.Site.cookieName + "=" + cartID + expires + ";domain=.postnl.nl;path=/";
    },

    // Post to the API. response contains a cartID in which we can place items
    createNewCart: function(productID, amount) {
        // console.log('createNewCart()');

        $.ajax({
            type: "POST",
            url: ECOM.Site.endPoint,
            error: function(error) {
                ECOM.Site.doneLoading('error');
            },
            success: function(result) {
                // set the cookie with the cartID
                var cartID = result.replace(/['"]+/g, '');
                ECOM.Site.setCookie(cartID);

                if (productID) {
                    // Cart exists now, so add the clicked item to the cart
                    ECOM.Site.addToExistingCart(productID, amount);
                }
            }
        });
    },

    // add product to the cart
    addToExistingCart: function(productID, amount) {
        // console.log('addToExistingCart()');
        var addToCartEndpoint = ECOM.Site.endPoint + ECOM.Site.customerCartId + '/items';
        var cart = {
            "cartItem": {
                "quoteId": ECOM.Site.customerCartId,
                "sku": productID,
                "qty": amount
            }
        };
        var data = {
            'data': cart
        };

        $.ajax({
            type: "POST",
            url: addToCartEndpoint,
            data: data,
            error: function(error) {
                ECOM.Site.doneLoading('error');
            },
            success: function(result) {
                ECOM.Site.doneLoading('success');
                ECOM.Site.updateCartCounter(amount);
            }
        });
    },

    doneLoading: function(state) {
        // console.log('doneLoading()');
        ECOM.Site.busyButton.removeClass(ECOM.Site.loadingClass);

        if (state === 'success') {
            ECOM.Site.busyButton.addClass(ECOM.Site.doneClass);
            // console.log('doneLoading(success)');
            setTimeout(function() {
                ECOM.Site.busyButton.removeClass(ECOM.Site.doneClass);
                ECOM.Site.busyButton = null;
                // console.log('doneLoading(done)');
            }, 1200);
        } else {
            // console.log('doneLoading(error)');
            ECOM.Site.busyButton.addClass(ECOM.Site.errorClass);
            setTimeout(function() {
                ECOM.Site.busyButton.removeClass(ECOM.Site.errorClass);
                ECOM.Site.busyButton = null;
                // console.log('doneLoading(done)');
            }, 1200);
        }
    },

    updateCartCounter: function(amount) {
        // JWB: Following code set's or updates the cart counter.
        //      Due time constraints and deadlines this was changed to just
        //      a (in)active cart.
        // if ($('.cart-counter').length) {
        //     var counter = +($('.cart-counter').text());
        //     counter += amount;
        //     $('.cart-counter').text(counter);
        // }
        // else {
        //     $('.icon-cart').append('<span class="cart-counter">'+amount+'</span>');
        // }

        if (PNLNav && PNLNav.hasOwnProperty('Cart')) {
            if ($('.cart-counter').length) {
                var counter = +($('.cart-counter').text());
                counter += amount;
                if (counter) {
                    // More then 0 products -> active cart
                    PNLNav.Cart.showActiveCart();
                } else {
                    // 0 products -> inactive cart
                    PNLNav.Cart.showInActiveCart();
                }
            } else {
                PNLNav.Cart.showActiveCart();
            }
        }

    }


};
$(document).ready(ECOM.Site.init);

