/* Minification failed. Returning unminified contents.
(2774,21-22): run-time error JS1014: Invalid character: `
(2775,17-18): run-time error JS1195: Expected expression: <
(2776,110-111): run-time error JS1195: Expected expression: <
(2777,138-139): run-time error JS1197: Too many errors. The file might not be a JavaScript file: <
(2767,5-24): run-time error JS1301: End of file encountered before function is properly closed: function bindData()
(2778,17-18): run-time error JS1195: Expected expression: <
(2778,18-19): run-time error JS1197: Too many errors. The file might not be a JavaScript file: /
(2652,1-26): run-time error JS1301: End of file encountered before function is properly closed: function tagsModule(elem)
(2779,13-14): run-time error JS1014: Invalid character: `
(2779,14-15): run-time error JS1195: Expected expression: ;
(2780,9-10): run-time error JS1002: Syntax error: }
(2782,9-13): run-time error JS1197: Too many errors. The file might not be a JavaScript file: that
 */
/* =========================================================
 * bootstrap-datepicker.js
 * Repo: https://github.com/eternicode/bootstrap-datepicker/
 * Demo: https://eternicode.github.io/bootstrap-datepicker/
 * Docs: https://bootstrap-datepicker.readthedocs.org/
 * Forked from http://www.eyecon.ro/bootstrap-datepicker
 * =========================================================
 * Started by Stefan Petre; improvements by Andrew Rowls + contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================= */

(function(factory){
    if (typeof define === "function" && define.amd) {
        define(["jquery"], factory);
    } else if (typeof exports === 'object') {
        factory(require('jquery'));
    } else {
        factory(jQuery);
    }
}(function($, undefined){

	function UTCDate(){
		return new Date(Date.UTC.apply(Date, arguments));
	}
	function UTCToday(){
		var today = new Date();
		return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
	}
	function isUTCEquals(date1, date2) {
		return (
			date1.getUTCFullYear() === date2.getUTCFullYear() &&
			date1.getUTCMonth() === date2.getUTCMonth() &&
			date1.getUTCDate() === date2.getUTCDate()
		);
	}
	function alias(method){
		return function(){
			return this[method].apply(this, arguments);
		};
	}
	function isValidDate(d) {
		return d && !isNaN(d.getTime());
	}

	var DateArray = (function(){
		var extras = {
			get: function(i){
				return this.slice(i)[0];
			},
			contains: function(d){
				// Array.indexOf is not cross-browser;
				// $.inArray doesn't work with Dates
				var val = d && d.valueOf();
				for (var i=0, l=this.length; i < l; i++)
          // Use date arithmetic to allow dates with different times to match
          if (0 <= this[i].valueOf() - val && this[i].valueOf() - val < 1000*60*60*24)
						return i;
				return -1;
			},
			remove: function(i){
				this.splice(i,1);
			},
			replace: function(new_array){
				if (!new_array)
					return;
				if (!$.isArray(new_array))
					new_array = [new_array];
				this.clear();
				this.push.apply(this, new_array);
			},
			clear: function(){
				this.length = 0;
			},
			copy: function(){
				var a = new DateArray();
				a.replace(this);
				return a;
			}
		};

		return function(){
			var a = [];
			a.push.apply(a, arguments);
			$.extend(a, extras);
			return a;
		};
	})();


	// Picker object

	var Datepicker = function(element, options){
		$.data(element, 'datepicker', this);
		this._process_options(options);

		this.dates = new DateArray();
		this.viewDate = this.o.defaultViewDate;
		this.focusDate = null;

		this.element = $(element);
		this.isInput = this.element.is('input');
		this.inputField = this.isInput ? this.element : this.element.find('input');
		this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .btn') : false;
		if (this.component && this.component.length === 0)
			this.component = false;
		this.isInline = !this.component && this.element.is('div');

		this.picker = $(DPGlobal.template);

		// Checking templates and inserting
		if (this._check_template(this.o.templates.leftArrow)) {
			this.picker.find('.prev').html(this.o.templates.leftArrow);
		}

		if (this._check_template(this.o.templates.rightArrow)) {
			this.picker.find('.next').html(this.o.templates.rightArrow);
		}

		this._buildEvents();
		this._attachEvents();

		if (this.isInline){
			this.picker.addClass('datepicker-inline').appendTo(this.element);
		}
		else {
			this.picker.addClass('datepicker-dropdown dropdown-menu');
		}

		if (this.o.rtl){
			this.picker.addClass('datepicker-rtl');
		}

		if (this.o.calendarWeeks) {
			this.picker.find('.datepicker-days .datepicker-switch, thead .datepicker-title, tfoot .today, tfoot .clear')
				.attr('colspan', function(i, val){
					return Number(val) + 1;
				});
		}

		this._allow_update = false;

		this.setStartDate(this._o.startDate);
		this.setEndDate(this._o.endDate);
		this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
		this.setDaysOfWeekHighlighted(this.o.daysOfWeekHighlighted);
		this.setDatesDisabled(this.o.datesDisabled);

		this.setViewMode(this.o.startView);
		this.fillDow();
		this.fillMonths();

		this._allow_update = true;

		this.update();

		if (this.isInline){
			this.show();
		}
	};

	Datepicker.prototype = {
		constructor: Datepicker,

		_resolveViewName: function(view){
			$.each(DPGlobal.viewModes, function(i, viewMode){
				if (view === i || $.inArray(view, viewMode.names) !== -1){
					view = i;
					return false;
				}
			});

			return view;
		},

		_resolveDaysOfWeek: function(daysOfWeek){
			if (!$.isArray(daysOfWeek))
				daysOfWeek = daysOfWeek.split(/[,\s]*/);
			return $.map(daysOfWeek, Number);
		},

		_check_template: function(tmp){
			try {
				// If empty
				if (tmp === undefined || tmp === "") {
					return false;
				}
				// If no html, everything ok
				if ((tmp.match(/[<>]/g) || []).length <= 0) {
					return true;
				}
				// Checking if html is fine
				var jDom = $(tmp);
				return jDom.length > 0;
			}
			catch (ex) {
				return false;
			}
		},

		_process_options: function(opts){
			// Store raw options for reference
			this._o = $.extend({}, this._o, opts);
			// Processed options
			var o = this.o = $.extend({}, this._o);

			// Check if "de-DE" style date is available, if not language should
			// fallback to 2 letter code eg "de"
			var lang = o.language;
			if (!dates[lang]){
				lang = lang.split('-')[0];
				if (!dates[lang])
					lang = defaults.language;
			}
			o.language = lang;

			// Retrieve view index from any aliases
			o.startView = this._resolveViewName(o.startView);
			o.minViewMode = this._resolveViewName(o.minViewMode);
			o.maxViewMode = this._resolveViewName(o.maxViewMode);

			// Check view is between min and max
			o.startView = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, o.startView));

			// true, false, or Number > 0
			if (o.multidate !== true){
				o.multidate = Number(o.multidate) || false;
				if (o.multidate !== false)
					o.multidate = Math.max(0, o.multidate);
			}
			o.multidateSeparator = String(o.multidateSeparator);

			o.weekStart %= 7;
			o.weekEnd = (o.weekStart + 6) % 7;

			var format = DPGlobal.parseFormat(o.format);
			if (o.startDate !== -Infinity){
				if (!!o.startDate){
					if (o.startDate instanceof Date)
						o.startDate = this._local_to_utc(this._zero_time(o.startDate));
					else
						o.startDate = DPGlobal.parseDate(o.startDate, format, o.language, o.assumeNearbyYear);
				}
				else {
					o.startDate = -Infinity;
				}
			}
			if (o.endDate !== Infinity){
				if (!!o.endDate){
					if (o.endDate instanceof Date)
						o.endDate = this._local_to_utc(this._zero_time(o.endDate));
					else
						o.endDate = DPGlobal.parseDate(o.endDate, format, o.language, o.assumeNearbyYear);
				}
				else {
					o.endDate = Infinity;
				}
			}

			o.daysOfWeekDisabled = this._resolveDaysOfWeek(o.daysOfWeekDisabled||[]);
			o.daysOfWeekHighlighted = this._resolveDaysOfWeek(o.daysOfWeekHighlighted||[]);

			o.datesDisabled = o.datesDisabled||[];
			if (!$.isArray(o.datesDisabled)) {
				o.datesDisabled = [
					o.datesDisabled
				];
			}
			o.datesDisabled = $.map(o.datesDisabled, function(d){
				return DPGlobal.parseDate(d, format, o.language, o.assumeNearbyYear);
			});

			var plc = String(o.orientation).toLowerCase().split(/\s+/g),
				_plc = o.orientation.toLowerCase();
			plc = $.grep(plc, function(word){
				return /^auto|left|right|top|bottom$/.test(word);
			});
			o.orientation = {x: 'auto', y: 'auto'};
			if (!_plc || _plc === 'auto')
				; // no action
			else if (plc.length === 1){
				switch (plc[0]){
					case 'top':
					case 'bottom':
						o.orientation.y = plc[0];
						break;
					case 'left':
					case 'right':
						o.orientation.x = plc[0];
						break;
				}
			}
			else {
				_plc = $.grep(plc, function(word){
					return /^left|right$/.test(word);
				});
				o.orientation.x = _plc[0] || 'auto';

				_plc = $.grep(plc, function(word){
					return /^top|bottom$/.test(word);
				});
				o.orientation.y = _plc[0] || 'auto';
			}
			if (o.defaultViewDate) {
				var year = o.defaultViewDate.year || new Date().getFullYear();
				var month = o.defaultViewDate.month || 0;
				var day = o.defaultViewDate.day || 1;
				o.defaultViewDate = UTCDate(year, month, day);
			} else {
				o.defaultViewDate = UTCToday();
			}
		},
		_events: [],
		_secondaryEvents: [],
		_applyEvents: function(evs){
			for (var i=0, el, ch, ev; i < evs.length; i++){
				el = evs[i][0];
				if (evs[i].length === 2){
					ch = undefined;
					ev = evs[i][1];
				} else if (evs[i].length === 3){
					ch = evs[i][1];
					ev = evs[i][2];
				}
				el.on(ev, ch);
			}
		},
		_unapplyEvents: function(evs){
			for (var i=0, el, ev, ch; i < evs.length; i++){
				el = evs[i][0];
				if (evs[i].length === 2){
					ch = undefined;
					ev = evs[i][1];
				} else if (evs[i].length === 3){
					ch = evs[i][1];
					ev = evs[i][2];
				}
				el.off(ev, ch);
			}
		},
		_buildEvents: function(){
            var events = {
                keyup: $.proxy(function(e){
                    if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
                        this.update();
                }, this),
                keydown: $.proxy(this.keydown, this),
                paste: $.proxy(this.paste, this)
            };

            if (this.o.showOnFocus === true) {
                events.focus = $.proxy(this.show, this);
            }

            if (this.isInput) { // single input
                this._events = [
                    [this.element, events]
                ];
            }
            // component: input + button
            else if (this.component && this.inputField.length) {
                this._events = [
                    // For components that are not readonly, allow keyboard nav
                    [this.inputField, events],
                    [this.component, {
                        click: $.proxy(this.show, this)
                    }]
                ];
            }
			else {
				this._events = [
					[this.element, {
						click: $.proxy(this.show, this),
						keydown: $.proxy(this.keydown, this)
					}]
				];
			}
			this._events.push(
				// Component: listen for blur on element descendants
				[this.element, '*', {
					blur: $.proxy(function(e){
						this._focused_from = e.target;
					}, this)
				}],
				// Input: listen for blur on element
				[this.element, {
					blur: $.proxy(function(e){
						this._focused_from = e.target;
					}, this)
				}]
			);

			if (this.o.immediateUpdates) {
				// Trigger input updates immediately on changed year/month
				this._events.push([this.element, {
					'changeYear changeMonth': $.proxy(function(e){
						this.update(e.date);
					}, this)
				}]);
			}

			this._secondaryEvents = [
				[this.picker, {
					click: $.proxy(this.click, this)
				}],
				[this.picker, '.prev, .next', {
					click: $.proxy(this.navArrowsClick, this)
				}],
				[$(window), {
					resize: $.proxy(this.place, this)
				}],
				[$(document), {
					'mousedown touchstart': $.proxy(function(e){
						// Clicked outside the datepicker, hide it
						if (!(
							this.element.is(e.target) ||
							this.element.find(e.target).length ||
							this.picker.is(e.target) ||
							this.picker.find(e.target).length ||
							this.isInline
						)){
							this.hide();
						}
					}, this)
				}]
			];
		},
		_attachEvents: function(){
			this._detachEvents();
			this._applyEvents(this._events);
		},
		_detachEvents: function(){
			this._unapplyEvents(this._events);
		},
		_attachSecondaryEvents: function(){
			this._detachSecondaryEvents();
			this._applyEvents(this._secondaryEvents);
		},
		_detachSecondaryEvents: function(){
			this._unapplyEvents(this._secondaryEvents);
		},
		_trigger: function(event, altdate){
			var date = altdate || this.dates.get(-1),
				local_date = this._utc_to_local(date);

			this.element.trigger({
				type: event,
				date: local_date,
				dates: $.map(this.dates, this._utc_to_local),
				format: $.proxy(function(ix, format){
					if (arguments.length === 0){
						ix = this.dates.length - 1;
						format = this.o.format;
					} else if (typeof ix === 'string'){
						format = ix;
						ix = this.dates.length - 1;
					}
					format = format || this.o.format;
					var date = this.dates.get(ix);
					return DPGlobal.formatDate(date, format, this.o.language);
				}, this)
			});
		},

		show: function(){
			if (this.inputField.prop('disabled') || (this.inputField.prop('readonly') && this.o.enableOnReadonly === false))
				return;
			if (!this.isInline)
				this.picker.appendTo(this.o.container);
			this.place();
			this.picker.show();
			this._attachSecondaryEvents();
			this._trigger('show');
			if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) {
				$(this.element).blur();
			}
			return this;
		},

		hide: function(){
			if (this.isInline || !this.picker.is(':visible'))
				return this;
			this.focusDate = null;
			this.picker.hide().detach();
			this._detachSecondaryEvents();
			this.setViewMode(this.o.startView);

			if (this.o.forceParse && this.inputField.val())
				this.setValue();
			this._trigger('hide');
			return this;
		},

		destroy: function(){
			this.hide();
			this._detachEvents();
			this._detachSecondaryEvents();
			this.picker.remove();
			delete this.element.data().datepicker;
			if (!this.isInput){
				delete this.element.data().date;
			}
			return this;
		},

		paste: function(e){
			var dateString;
			if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.types
				&& $.inArray('text/plain', e.originalEvent.clipboardData.types) !== -1) {
				dateString = e.originalEvent.clipboardData.getData('text/plain');
			} else if (window.clipboardData) {
				dateString = window.clipboardData.getData('Text');
			} else {
				return;
			}
			this.setDate(dateString);
			this.update();
			e.preventDefault();
		},

		_utc_to_local: function(utc){
			return utc && new Date(utc.getTime() + (utc.getTimezoneOffset()*60000));
		},
		_local_to_utc: function(local){
			return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
		},
		_zero_time: function(local){
			return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
		},
		_zero_utc_time: function(utc){
			return utc && UTCDate(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());
		},

		getDates: function(){
			return $.map(this.dates, this._utc_to_local);
		},

		getUTCDates: function(){
			return $.map(this.dates, function(d){
				return new Date(d);
			});
		},

		getDate: function(){
			return this._utc_to_local(this.getUTCDate());
		},

		getUTCDate: function(){
			var selected_date = this.dates.get(-1);
			if (selected_date !== undefined) {
				return new Date(selected_date);
			} else {
				return null;
			}
		},

		clearDates: function(){
			this.inputField.val('');
			this.update();
			this._trigger('changeDate');

			if (this.o.autoclose) {
				this.hide();
			}
		},

		setDates: function(){
			var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
			this.update.apply(this, args);
			this._trigger('changeDate');
			this.setValue();
			return this;
		},

		setUTCDates: function(){
			var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
			this.setDates.apply(this, $.map(args, this._utc_to_local));
			return this;
		},

		setDate: alias('setDates'),
		setUTCDate: alias('setUTCDates'),
		remove: alias('destroy'),

		setValue: function(){
			var formatted = this.getFormattedDate();
			this.inputField.val(formatted);
			return this;
		},

		getFormattedDate: function(format){
			if (format === undefined)
				format = this.o.format;

			var lang = this.o.language;
			return $.map(this.dates, function(d){
				return DPGlobal.formatDate(d, format, lang);
			}).join(this.o.multidateSeparator);
		},

		getStartDate: function(){
			return this.o.startDate;
		},

		setStartDate: function(startDate){
			this._process_options({startDate: startDate});
			this.update();
			this.updateNavArrows();
			return this;
		},

		getEndDate: function(){
			return this.o.endDate;
		},

		setEndDate: function(endDate){
			this._process_options({endDate: endDate});
			this.update();
			this.updateNavArrows();
			return this;
		},

		setDaysOfWeekDisabled: function(daysOfWeekDisabled){
			this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
			this.update();
			return this;
		},

		setDaysOfWeekHighlighted: function(daysOfWeekHighlighted){
			this._process_options({daysOfWeekHighlighted: daysOfWeekHighlighted});
			this.update();
			return this;
		},

		setDatesDisabled: function(datesDisabled){
			this._process_options({datesDisabled: datesDisabled});
			this.update();
			return this;
		},

		place: function(){
			if (this.isInline)
				return this;
			var calendarWidth = this.picker.outerWidth(),
				calendarHeight = this.picker.outerHeight(),
				visualPadding = 10,
				container = $(this.o.container),
				windowWidth = container.width(),
				scrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(),
				appendOffset = container.offset();

			var parentsZindex = [];
			this.element.parents().each(function(){
				var itemZIndex = $(this).css('z-index');
				if (itemZIndex !== 'auto' && itemZIndex !== 0) parentsZindex.push(parseInt(itemZIndex));
			});
			var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset;
			var offset = this.component ? this.component.parent().offset() : this.element.offset();
			var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
			var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
			var left = offset.left - appendOffset.left,
				top = offset.top - appendOffset.top;

			if (this.o.container !== 'body') {
				top += scrollTop;
			}

			this.picker.removeClass(
				'datepicker-orient-top datepicker-orient-bottom '+
				'datepicker-orient-right datepicker-orient-left'
			);

			if (this.o.orientation.x !== 'auto'){
				this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
				if (this.o.orientation.x === 'right')
					left -= calendarWidth - width;
			}
			// auto x orientation is best-placement: if it crosses a window
			// edge, fudge it sideways
			else {
				if (offset.left < 0) {
					// component is outside the window on the left side. Move it into visible range
					this.picker.addClass('datepicker-orient-left');
					left -= offset.left - visualPadding;
				} else if (left + calendarWidth > windowWidth) {
					// the calendar passes the widow right edge. Align it to component right side
					this.picker.addClass('datepicker-orient-right');
					left += width - calendarWidth;
				} else {
					// Default to left
					this.picker.addClass('datepicker-orient-left');
				}
			}

			// auto y orientation is best-situation: top or bottom, no fudging,
			// decision based on which shows more of the calendar
			var yorient = this.o.orientation.y,
				top_overflow;
			if (yorient === 'auto'){
				top_overflow = -scrollTop + top - calendarHeight;
				yorient = top_overflow < 0 ? 'bottom' : 'top';
			}

			this.picker.addClass('datepicker-orient-' + yorient);
			if (yorient === 'top')
				top -= calendarHeight + parseInt(this.picker.css('padding-top'));
			else
				top += height;

			if (this.o.rtl) {
				var right = windowWidth - (left + width);
				this.picker.css({
					top: top,
					right: right,
					zIndex: zIndex
				});
			} else {
				this.picker.css({
					top: top,
					left: left,
					zIndex: zIndex
				});
			}
			return this;
		},

		_allow_update: true,
		update: function(){
			if (!this._allow_update)
				return this;

			var oldDates = this.dates.copy(),
				dates = [],
				fromArgs = false;
			if (arguments.length){
				$.each(arguments, $.proxy(function(i, date){
					if (date instanceof Date)
						date = this._local_to_utc(date);
					dates.push(date);
				}, this));
				fromArgs = true;
			} else {
				dates = this.isInput
						? this.element.val()
						: this.element.data('date') || this.inputField.val();
				if (dates && this.o.multidate)
					dates = dates.split(this.o.multidateSeparator);
				else
					dates = [dates];
				delete this.element.data().date;
			}

			dates = $.map(dates, $.proxy(function(date){
				return DPGlobal.parseDate(date, this.o.format, this.o.language, this.o.assumeNearbyYear);
			}, this));
			dates = $.grep(dates, $.proxy(function(date){
				return (
					!this.dateWithinRange(date) ||
					!date
				);
			}, this), true);
			this.dates.replace(dates);

			if (this.dates.length)
				this.viewDate = new Date(this.dates.get(-1));
			else if (this.viewDate < this.o.startDate)
				this.viewDate = new Date(this.o.startDate);
			else if (this.viewDate > this.o.endDate)
				this.viewDate = new Date(this.o.endDate);
			else
				this.viewDate = this.o.defaultViewDate;

			if (fromArgs){
				// setting date by clicking
				this.setValue();
				this.element.change();
			}
			else if (this.dates.length){
				// setting date by typing
				if (String(oldDates) !== String(this.dates) && fromArgs) {
					this._trigger('changeDate');
					this.element.change();
				}
			}
			if (!this.dates.length && oldDates.length) {
				this._trigger('clearDate');
				this.element.change();
			}

			this.fill();
			return this;
		},

		fillDow: function(){
			var dowCnt = this.o.weekStart,
				html = '<tr>';
			if (this.o.calendarWeeks){
				html += '<th class="cw">&#160;</th>';
			}
			while (dowCnt < this.o.weekStart + 7){
				html += '<th class="dow';
        if ($.inArray(dowCnt, this.o.daysOfWeekDisabled) !== -1)
          html += ' disabled';
        html += '">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
			}
			html += '</tr>';
			this.picker.find('.datepicker-days thead').append(html);
		},

		fillMonths: function(){
      var localDate = this._utc_to_local(this.viewDate);
			var html = '',
			i = 0;
			while (i < 12){
        var focused = localDate && localDate.getMonth() === i ? ' focused' : '';
				html += '<span class="month' + focused + '">' + dates[this.o.language].monthsShort[i++]+'</span>';
			}
			this.picker.find('.datepicker-months td').html(html);
		},

		setRange: function(range){
			if (!range || !range.length)
				delete this.range;
			else
				this.range = $.map(range, function(d){
					return d.valueOf();
				});
			this.fill();
		},

		getClassNames: function(date){
			var cls = [],
				year = this.viewDate.getUTCFullYear(),
				month = this.viewDate.getUTCMonth(),
				today = UTCToday();
			if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
				cls.push('old');
			} else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
				cls.push('new');
			}
			if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
				cls.push('focused');
			// Compare internal UTC date with UTC today, not local today
			if (this.o.todayHighlight && isUTCEquals(date, today)) {
				cls.push('today');
			}
			if (this.dates.contains(date) !== -1)
				cls.push('active');
			if (!this.dateWithinRange(date)){
				cls.push('disabled');
			}
			if (this.dateIsDisabled(date)){
				cls.push('disabled', 'disabled-date');
			}
			if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1){
				cls.push('highlighted');
			}

			if (this.range){
				if (date > this.range[0] && date < this.range[this.range.length-1]){
					cls.push('range');
				}
				if ($.inArray(date.valueOf(), this.range) !== -1){
					cls.push('selected');
				}
				if (date.valueOf() === this.range[0]){
          cls.push('range-start');
        }
        if (date.valueOf() === this.range[this.range.length-1]){
          cls.push('range-end');
        }
			}
			return cls;
		},

		_fill_yearsView: function(selector, cssClass, factor, step, currentYear, startYear, endYear, callback){
			var html, view, year, steps, startStep, endStep, thisYear, i, classes, tooltip, before;

			html      = '';
			view      = this.picker.find(selector);
			year      = parseInt(currentYear / factor, 10) * factor;
			startStep = parseInt(startYear / step, 10) * step;
			endStep   = parseInt(endYear / step, 10) * step;
			steps     = $.map(this.dates, function(d){
				return parseInt(d.getUTCFullYear() / step, 10) * step;
			});

			view.find('.datepicker-switch').text(year + '-' + (year + step * 9));

			thisYear = year - step;
			for (i = -1; i < 11; i += 1) {
				classes = [cssClass];
				tooltip = null;

				if (i === -1) {
					classes.push('old');
				} else if (i === 10) {
					classes.push('new');
				}
				if ($.inArray(thisYear, steps) !== -1) {
					classes.push('active');
				}
				if (thisYear < startStep || thisYear > endStep) {
					classes.push('disabled');
				}
        if (thisYear === this.viewDate.getFullYear()) {
				  classes.push('focused');
        }

				if (callback !== $.noop) {
					before = callback(new Date(thisYear, 0, 1));
					if (before === undefined) {
						before = {};
					} else if (typeof before === 'boolean') {
						before = {enabled: before};
					} else if (typeof before === 'string') {
						before = {classes: before};
					}
					if (before.enabled === false) {
						classes.push('disabled');
					}
					if (before.classes) {
						classes = classes.concat(before.classes.split(/\s+/));
					}
					if (before.tooltip) {
						tooltip = before.tooltip;
					}
				}

				html += '<span class="' + classes.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + '>' + thisYear + '</span>';
				thisYear += step;
			}
			view.find('td').html(html);
		},

		fill: function(){
			var d = new Date(this.viewDate),
				year = d.getUTCFullYear(),
				month = d.getUTCMonth(),
				startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
				startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
				endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
				endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
				todaytxt = dates[this.o.language].today || dates['en'].today || '',
				cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
				titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat,
				tooltip,
				before;
			if (isNaN(year) || isNaN(month))
				return;
			this.picker.find('.datepicker-days .datepicker-switch')
						.text(DPGlobal.formatDate(d, titleFormat, this.o.language));
			this.picker.find('tfoot .today')
						.text(todaytxt)
						.toggle(this.o.todayBtn !== false);
			this.picker.find('tfoot .clear')
						.text(cleartxt)
						.toggle(this.o.clearBtn !== false);
			this.picker.find('thead .datepicker-title')
						.text(this.o.title)
						.toggle(this.o.title !== '');
			this.updateNavArrows();
			this.fillMonths();
			var prevMonth = UTCDate(year, month, 0),
				day = prevMonth.getUTCDate();
			prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
			var nextMonth = new Date(prevMonth);
			if (prevMonth.getUTCFullYear() < 100){
        nextMonth.setUTCFullYear(prevMonth.getUTCFullYear());
      }
			nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
			nextMonth = nextMonth.valueOf();
			var html = [];
			var weekDay, clsName;
			while (prevMonth.valueOf() < nextMonth){
				weekDay = prevMonth.getUTCDay();
				if (weekDay === this.o.weekStart){
					html.push('<tr>');
					if (this.o.calendarWeeks){
						// ISO 8601: First week contains first thursday.
						// ISO also states week starts on Monday, but we can be more abstract here.
						var
							// Start of current week: based on weekstart/current date
							ws = new Date(+prevMonth + (this.o.weekStart - weekDay - 7) % 7 * 864e5),
							// Thursday of this week
							th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
							// First Thursday of year, year from thursday
							yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5),
							// Calendar week: ms between thursdays, div ms per day, div 7 days
							calWeek = (th - yth) / 864e5 / 7 + 1;
						html.push('<td class="cw">'+ calWeek +'</td>');
					}
				}
				clsName = this.getClassNames(prevMonth);
				clsName.push('day');

				if (this.o.beforeShowDay !== $.noop){
					before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
					if (before === undefined)
						before = {};
					else if (typeof before === 'boolean')
						before = {enabled: before};
					else if (typeof before === 'string')
						before = {classes: before};
					if (before.enabled === false)
						clsName.push('disabled');
					if (before.classes)
						clsName = clsName.concat(before.classes.split(/\s+/));
					if (before.tooltip)
						tooltip = before.tooltip;
				}

				// $.unique is deprecated on jQuery 3.x
				clsName = $.unique(clsName);

				html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + (this.o.dateCells ? ' data-date="'+(prevMonth.getTime().toString())+'"' : '') + '>'+prevMonth.getUTCDate() + '</td>');
				tooltip = null;
				if (weekDay === this.o.weekEnd){
					html.push('</tr>');
				}
				prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
			}
			this.picker.find('.datepicker-days tbody').html(html.join(''));

			var monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months';
			var months = this.picker.find('.datepicker-months')
						.find('.datepicker-switch')
							.text(this.o.maxViewMode < 2 ? monthsTitle : year)
							.end()
						.find('tbody span').removeClass('active');

			$.each(this.dates, function(i, d){
				if (d.getUTCFullYear() === year)
					months.eq(d.getUTCMonth()).addClass('active');
			});

			if (year < startYear || year > endYear){
				months.addClass('disabled');
			}
			if (year === startYear){
				months.slice(0, startMonth).addClass('disabled');
			}
			if (year === endYear){
				months.slice(endMonth+1).addClass('disabled');
			}

			if (this.o.beforeShowMonth !== $.noop){
				var that = this;
				$.each(months, function(i, month){
          var moDate = new Date(year, i, 1);
          var before = that.o.beforeShowMonth(moDate);
					if (before === undefined)
						before = {};
					else if (typeof before === 'boolean')
						before = {enabled: before};
					else if (typeof before === 'string')
						before = {classes: before};
					if (before.enabled === false && !$(month).hasClass('disabled'))
					    $(month).addClass('disabled');
					if (before.classes)
					    $(month).addClass(before.classes);
					if (before.tooltip)
					    $(month).prop('title', before.tooltip);
				});
			}

			// Generating decade/years picker
			this._fill_yearsView(
				'.datepicker-years',
				'year',
				10,
				1,
				year,
				startYear,
				endYear,
				this.o.beforeShowYear
			);

			// Generating century/decades picker
			this._fill_yearsView(
				'.datepicker-decades',
				'decade',
				100,
				10,
				year,
				startYear,
				endYear,
				this.o.beforeShowDecade
			);

			// Generating millennium/centuries picker
			this._fill_yearsView(
				'.datepicker-centuries',
				'century',
				1000,
				100,
				year,
				startYear,
				endYear,
				this.o.beforeShowCentury
			);
		},

		updateNavArrows: function(){
			if (!this._allow_update)
				return;

			var d = new Date(this.viewDate),
				year = d.getUTCFullYear(),
				month = d.getUTCMonth(),
				prevState,
				nextState;
			switch (this.viewMode){
				case 0:
					prevState = (
						this.o.startDate !== -Infinity &&
						year <= this.o.startDate.getUTCFullYear() &&
						month <= this.o.startDate.getUTCMonth()
					);

					nextState = (
						this.o.endDate !== Infinity &&
						year >= this.o.endDate.getUTCFullYear() &&
						month >= this.o.endDate.getUTCMonth()
					);
					break;
				case 1:
				case 2:
				case 3:
				case 4:
					prevState = (
						this.o.startDate !== -Infinity &&
						year <= this.o.startDate.getUTCFullYear()
					);

					nextState = (
						this.o.endDate !== Infinity &&
						year >= this.o.endDate.getUTCFullYear()
					);
					break;
			}

			this.picker.find('.prev').toggleClass('disabled', prevState);
			this.picker.find('.next').toggleClass('disabled', nextState);
		},

		click: function(e){
			e.preventDefault();
			e.stopPropagation();

			var target, dir, day, year, month;
			target = $(e.target);

			// Clicked on the switch
			if (target.hasClass('datepicker-switch')){
				this.setViewMode(this.viewMode + 1);
			}

			// Clicked on today button
			if (target.hasClass('today') && !target.hasClass('day')){
				this.setViewMode(0);
				this._setDate(UTCToday(), this.o.todayBtn === 'linked' ? null : 'view');
			}

			// Clicked on clear button
			if (target.hasClass('clear')){
				this.clearDates();
			}

			if (!target.hasClass('disabled')){
				// Clicked on a day
				if (target.hasClass('day')){
					day = Number(target.text());
					year = this.viewDate.getUTCFullYear();
					month = this.viewDate.getUTCMonth();

					if (target.hasClass('old') || target.hasClass('new')){
						dir = target.hasClass('old') ? -1 : 1;
						month = (month + dir + 12) % 12;
						if ((dir === -1 && month === 11) || (dir === 1 && month === 0)) {
							year += dir;
							this._trigger('changeYear', this.viewDate);
						}
						this._trigger('changeMonth', this.viewDate);
					}
					this._setDate(UTCDate(year, month, day));
				}

				// Clicked on a month, year, decade, century
				if (target.hasClass('month')
						|| target.hasClass('year')
						|| target.hasClass('decade')
						|| target.hasClass('century')) {
					this.viewDate.setUTCDate(1);

					day = 1;
					if (this.viewMode === 1){
						month = target.parent().find('span').index(target);
						year = this.viewDate.getUTCFullYear();
						this.viewDate.setUTCMonth(month);
					} else {
						month = 0;
						year = Number(target.text());
						this.viewDate.setUTCFullYear(year);
					}

					this._trigger(DPGlobal.viewModes[this.viewMode - 1].e, this.viewDate);

					if (this.viewMode === this.o.minViewMode){
						this._setDate(UTCDate(year, month, day));
					} else {
						this.setViewMode(this.viewMode - 1);
						this.fill();
					}
				}
			}

			if (this.picker.is(':visible') && this._focused_from){
				this._focused_from.focus();
			}
			delete this._focused_from;
		},

		// Clicked on prev or next
		navArrowsClick: function(e){
			var target = $(e.target);
			var dir = target.hasClass('prev') ? -1 : 1;
			if (this.viewMode !== 0){
				dir *= DPGlobal.viewModes[this.viewMode].navStep * 12;
			}
			this.viewDate = this.moveMonth(this.viewDate, dir);
			this._trigger(DPGlobal.viewModes[this.viewMode].e, this.viewDate);
			this.fill();
		},

		_toggle_multidate: function(date){
			var ix = this.dates.contains(date);
			if (!date){
				this.dates.clear();
			}

			if (ix !== -1){
				if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive){
					this.dates.remove(ix);
				}
			} else if (this.o.multidate === false) {
				this.dates.clear();
				this.dates.push(date);
			}
			else {
				this.dates.push(date);
			}

			if (typeof this.o.multidate === 'number')
				while (this.dates.length > this.o.multidate)
					this.dates.remove(0);
		},

		_setDate: function(date, which){
			if (!which || which === 'date')
				this._toggle_multidate(date && new Date(date));
			if (!which || which === 'view')
				this.viewDate = date && new Date(date);

			this.fill();
			this.setValue();
			if (!which || which !== 'view') {
				this._trigger('changeDate');
			}
			this.inputField.trigger('change');
			if (this.o.autoclose && (!which || which === 'date')){
				this.hide();
			}
		},

		moveDay: function(date, dir){
			var newDate = new Date(date);
			newDate.setUTCDate(date.getUTCDate() + dir);

			return newDate;
		},

		moveWeek: function(date, dir){
			return this.moveDay(date, dir * 7);
		},

		moveMonth: function(date, dir){
			if (!isValidDate(date))
				return this.o.defaultViewDate;
			if (!dir)
				return date;
			var new_date = new Date(date.valueOf()),
				day = new_date.getUTCDate(),
				month = new_date.getUTCMonth(),
				mag = Math.abs(dir),
				new_month, test;
			dir = dir > 0 ? 1 : -1;
			if (mag === 1){
				test = dir === -1
					// If going back one month, make sure month is not current month
					// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
					? function(){
						return new_date.getUTCMonth() === month;
					}
					// If going forward one month, make sure month is as expected
					// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
					: function(){
						return new_date.getUTCMonth() !== new_month;
					};
				new_month = month + dir;
				new_date.setUTCMonth(new_month);
				// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
				new_month = (new_month + 12) % 12;
			}
			else {
				// For magnitudes >1, move one month at a time...
				for (var i=0; i < mag; i++)
					// ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
					new_date = this.moveMonth(new_date, dir);
				// ...then reset the day, keeping it in the new month
				new_month = new_date.getUTCMonth();
				new_date.setUTCDate(day);
				test = function(){
					return new_month !== new_date.getUTCMonth();
				};
			}
			// Common date-resetting loop -- if date is beyond end of month, make it
			// end of month
			while (test()){
				new_date.setUTCDate(--day);
				new_date.setUTCMonth(new_month);
			}
			return new_date;
		},

		moveYear: function(date, dir){
			return this.moveMonth(date, dir*12);
		},

		moveAvailableDate: function(date, dir, fn){
			do {
				date = this[fn](date, dir);

				if (!this.dateWithinRange(date))
					return false;

				fn = 'moveDay';
			}
			while (this.dateIsDisabled(date));

			return date;
		},

		weekOfDateIsDisabled: function(date){
			return $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1;
		},

		dateIsDisabled: function(date){
			return (
				this.weekOfDateIsDisabled(date) ||
				$.grep(this.o.datesDisabled, function(d){
					return isUTCEquals(date, d);
				}).length > 0
			);
		},

		dateWithinRange: function(date){
			return date >= this.o.startDate && date <= this.o.endDate;
		},

		keydown: function(e){
			if (!this.picker.is(':visible')){
				if (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker
					this.show();
					e.stopPropagation();
        }
				return;
			}
			var dateChanged = false,
				dir, newViewDate,
				focusDate = this.focusDate || this.viewDate;
			switch (e.keyCode){
				case 27: // escape
					if (this.focusDate){
						this.focusDate = null;
						this.viewDate = this.dates.get(-1) || this.viewDate;
						this.fill();
					}
					else
						this.hide();
					e.preventDefault();
					e.stopPropagation();
					break;
				case 37: // left
				case 38: // up
				case 39: // right
				case 40: // down
					if (!this.o.keyboardNavigation || this.o.daysOfWeekDisabled.length === 7)
						break;
					dir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1;
          if (this.viewMode === 0) {
  					if (e.ctrlKey){
  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');

  						if (newViewDate)
  							this._trigger('changeYear', this.viewDate);
  					} else if (e.shiftKey){
  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');

  						if (newViewDate)
  							this._trigger('changeMonth', this.viewDate);
  					} else if (e.keyCode === 37 || e.keyCode === 39){
  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveDay');
  					} else if (!this.weekOfDateIsDisabled(focusDate)){
  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveWeek');
  					}
          } else if (this.viewMode === 1) {
            if (e.keyCode === 38 || e.keyCode === 40) {
              dir = dir * 4;
            }
            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
          } else if (this.viewMode === 2) {
            if (e.keyCode === 38 || e.keyCode === 40) {
              dir = dir * 4;
            }
            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
          }
					if (newViewDate){
						this.focusDate = this.viewDate = newViewDate;
						this.setValue();
						this.fill();
						e.preventDefault();
					}
					break;
				case 13: // enter
					if (!this.o.forceParse)
						break;
					focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
					if (this.o.keyboardNavigation) {
						this._toggle_multidate(focusDate);
						dateChanged = true;
					}
					this.focusDate = null;
					this.viewDate = this.dates.get(-1) || this.viewDate;
					this.setValue();
					this.fill();
					if (this.picker.is(':visible')){
						e.preventDefault();
						e.stopPropagation();
						if (this.o.autoclose)
							this.hide();
					}
					break;
				case 9: // tab
					this.focusDate = null;
					this.viewDate = this.dates.get(-1) || this.viewDate;
					this.fill();
					this.hide();
					break;
			}
			if (dateChanged){
				if (this.dates.length)
					this._trigger('changeDate');
				else
					this._trigger('clearDate');
				this.inputField.trigger('change');
			}
		},

		setViewMode: function(viewMode){
			this.viewMode = viewMode;
			this.picker
				.children('div')
				.hide()
				.filter('.datepicker-' + DPGlobal.viewModes[this.viewMode].clsName)
					.show();
			this.updateNavArrows();
		}
	};

	var DateRangePicker = function(element, options){
		$.data(element, 'datepicker', this);
		this.element = $(element);
		this.inputs = $.map(options.inputs, function(i){
			return i.jquery ? i[0] : i;
		});
		delete options.inputs;

		this.keepEmptyValues = options.keepEmptyValues;
		delete options.keepEmptyValues;

		datepickerPlugin.call($(this.inputs), options)
			.on('changeDate', $.proxy(this.dateUpdated, this));

		this.pickers = $.map(this.inputs, function(i){
			return $.data(i, 'datepicker');
		});
		this.updateDates();
	};
	DateRangePicker.prototype = {
		updateDates: function(){
			this.dates = $.map(this.pickers, function(i){
				return i.getUTCDate();
			});
			this.updateRanges();
		},
		updateRanges: function(){
			var range = $.map(this.dates, function(d){
				return d.valueOf();
			});
			$.each(this.pickers, function(i, p){
				p.setRange(range);
			});
		},
		dateUpdated: function(e){
			// `this.updating` is a workaround for preventing infinite recursion
			// between `changeDate` triggering and `setUTCDate` calling.  Until
			// there is a better mechanism.
			if (this.updating)
				return;
			this.updating = true;

			var dp = $.data(e.target, 'datepicker');

			if (dp === undefined) {
				return;
			}

			var new_date = dp.getUTCDate(),
				keep_empty_values = this.keepEmptyValues,
				i = $.inArray(e.target, this.inputs),
				j = i - 1,
				k = i + 1,
				l = this.inputs.length;
			if (i === -1)
				return;

			$.each(this.pickers, function(i, p){
				if (!p.getUTCDate() && (p === dp || !keep_empty_values))
					p.setUTCDate(new_date);
			});

			if (new_date < this.dates[j]){
				// Date being moved earlier/left
				while (j >= 0 && new_date < this.dates[j]){
					this.pickers[j--].setUTCDate(new_date);
				}
			} else if (new_date > this.dates[k]){
				// Date being moved later/right
				while (k < l && new_date > this.dates[k]){
					this.pickers[k++].setUTCDate(new_date);
				}
			}
			this.updateDates();

			delete this.updating;
		},
		destroy: function(){
			$.map(this.pickers, function(p){ p.destroy(); });
			delete this.element.data().datepicker;
		},
		remove: alias('destroy')
	};

	function opts_from_el(el, prefix){
		// Derive options from element data-attrs
		var data = $(el).data(),
			out = {}, inkey,
			replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
		prefix = new RegExp('^' + prefix.toLowerCase());
		function re_lower(_,a){
			return a.toLowerCase();
		}
		for (var key in data)
			if (prefix.test(key)){
				inkey = key.replace(replace, re_lower);
				out[inkey] = data[key];
			}
		return out;
	}

	function opts_from_locale(lang){
		// Derive options from locale plugins
		var out = {};
		// Check if "de-DE" style date is available, if not language should
		// fallback to 2 letter code eg "de"
		if (!dates[lang]){
			lang = lang.split('-')[0];
			if (!dates[lang])
				return;
		}
		var d = dates[lang];
		$.each(locale_opts, function(i,k){
			if (k in d)
				out[k] = d[k];
		});
		return out;
	}

	var old = $.fn.datepicker;
	var datepickerPlugin = function(option){
		var args = Array.apply(null, arguments);
		args.shift();
		var internal_return;
		this.each(function(){
			var $this = $(this),
				data = $this.data('datepicker'),
				options = typeof option === 'object' && option;
			if (!data){
				var elopts = opts_from_el(this, 'date'),
					// Preliminary otions
					xopts = $.extend({}, defaults, elopts, options),
					locopts = opts_from_locale(xopts.language),
					// Options priority: js args, data-attrs, locales, defaults
					opts = $.extend({}, defaults, locopts, elopts, options);
				if ($this.hasClass('input-daterange') || opts.inputs){
					$.extend(opts, {
						inputs: opts.inputs || $this.find('input').toArray()
					});
					data = new DateRangePicker(this, opts);
				}
				else {
					data = new Datepicker(this, opts);
				}
				$this.data('datepicker', data);
			}
			if (typeof option === 'string' && typeof data[option] === 'function'){
				internal_return = data[option].apply(data, args);
			}
		});

		if (
			internal_return === undefined ||
			internal_return instanceof Datepicker ||
			internal_return instanceof DateRangePicker
		)
			return this;

		if (this.length > 1)
			throw new Error('Using only allowed for the collection of a single element (' + option + ' function)');
		else
			return internal_return;
	};
	$.fn.datepicker = datepickerPlugin;

	var defaults = $.fn.datepicker.defaults = {
		assumeNearbyYear: false,
		autoclose: false,
		beforeShowDay: $.noop,
		beforeShowMonth: $.noop,
		beforeShowYear: $.noop,
		beforeShowDecade: $.noop,
		beforeShowCentury: $.noop,
		calendarWeeks: false,
		clearBtn: false,
		toggleActive: false,
		daysOfWeekDisabled: [],
		daysOfWeekHighlighted: [],
		datesDisabled: [],
		endDate: Infinity,
		forceParse: true,
		format: 'mm/dd/yyyy',
		keepEmptyValues: false,
		keyboardNavigation: true,
		language: 'en',
		minViewMode: 0,
		maxViewMode: 4,
		multidate: false,
		multidateSeparator: ',',
		orientation: "auto",
		rtl: false,
		startDate: -Infinity,
		startView: 0,
		todayBtn: false,
		todayHighlight: false,
		weekStart: 0,
		disableTouchKeyboard: false,
		enableOnReadonly: true,
		showOnFocus: true,
		zIndexOffset: 10,
		container: 'body',
		immediateUpdates: false,
		dateCells:false,
		title: '',
		templates: {
			leftArrow: '&laquo;',
			rightArrow: '&raquo;'
		}
	};
	var locale_opts = $.fn.datepicker.locale_opts = [
		'format',
		'rtl',
		'weekStart'
	];
	$.fn.datepicker.Constructor = Datepicker;
	var dates = $.fn.datepicker.dates = {
		en: {
			days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
			daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
			daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
			months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
			monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
			today: "Today",
			clear: "Clear",
			titleFormat: "MM yyyy"
		}
	};

	var DPGlobal = {
		viewModes: [
			{
				names: ['days', 'month'],
				clsName: 'days',
				e: 'changeMonth'
			},
			{
				names: ['months', 'year'],
				clsName: 'months',
				e: 'changeYear',
				navStep: 1
			},
			{
				names: ['years', 'decade'],
				clsName: 'years',
				e: 'changeDecade',
				navStep: 10
			},
			{
				names: ['decades', 'century'],
				clsName: 'decades',
				e: 'changeCentury',
				navStep: 100
			},
			{
				names: ['centuries', 'millennium'],
				clsName: 'centuries',
				e: 'changeMillennium',
				navStep: 1000
			}
		],
		validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
		nonpunctuation: /[^ -\/:-@\u5e74\u6708\u65e5\[-`{-~\t\n\r]+/g,
		parseFormat: function(format){
			if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function')
                return format;
            // IE treats \0 as a string end in inputs (truncating the value),
			// so it's a bad format delimiter, anyway
			var separators = format.replace(this.validParts, '\0').split('\0'),
				parts = format.match(this.validParts);
			if (!separators || !separators.length || !parts || parts.length === 0){
				throw new Error("Invalid date format.");
			}
			return {separators: separators, parts: parts};
		},
		parseDate: function(date, format, language, assumeNearby){
			if (!date)
				return undefined;
			if (date instanceof Date)
				return date;
			if (typeof format === 'string')
				format = DPGlobal.parseFormat(format);
			if (format.toValue)
                return format.toValue(date, format, language);
            var part_re = /([\-+]\d+)([dmwy])/,
				parts = date.match(/([\-+]\d+)([dmwy])/g),
				fn_map = {
					d: 'moveDay',
					m: 'moveMonth',
					w: 'moveWeek',
					y: 'moveYear'
				},
				dateAliases = {
					yesterday: '-1d',
					today: '+0d',
					tomorrow: '+1d'
				},
				part, dir, i, fn;
			if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){
				date = new Date();
				for (i=0; i < parts.length; i++){
					part = part_re.exec(parts[i]);
					dir = parseInt(part[1]);
					fn = fn_map[part[2]];
					date = Datepicker.prototype[fn](date, dir);
				}
				return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
			}

			if (date in dateAliases) {
				date = dateAliases[date];
				parts = date.match(/([\-+]\d+)([dmwy])/g);

				if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){
					date = new Date();
					for (i=0; i < parts.length; i++){
						part = part_re.exec(parts[i]);
						dir = parseInt(part[1]);
						fn = fn_map[part[2]];
						date = Datepicker.prototype[fn](date, dir);
					}

					return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
				}
			}

			parts = date && date.match(this.nonpunctuation) || [];
			date = new Date();

			function applyNearbyYear(year, threshold){
				if (threshold === true)
					threshold = 10;

				// if year is 2 digits or less, than the user most likely is trying to get a recent century
				if (year < 100){
					year += 2000;
					// if the new year is more than threshold years in advance, use last century
					if (year > ((new Date()).getFullYear()+threshold)){
						year -= 100;
					}
				}

				return year;
			}

			var parsed = {},
				setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
				setters_map = {
					yyyy: function(d,v){
						return d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v);
					},
					m: function(d,v){
						if (isNaN(d))
							return d;
						v -= 1;
						while (v < 0) v += 12;
						v %= 12;
						d.setUTCMonth(v);
						while (d.getUTCMonth() !== v)
							d.setUTCDate(d.getUTCDate()-1);
						return d;
					},
					d: function(d,v){
						return d.setUTCDate(v);
					}
				},
				val, filtered;
			setters_map['yy'] = setters_map['yyyy'];
			setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
			setters_map['dd'] = setters_map['d'];
			date = UTCToday();
			var fparts = format.parts.slice();
			// Remove noop parts
			if (parts.length !== fparts.length){
				fparts = $(fparts).filter(function(i,p){
					return $.inArray(p, setters_order) !== -1;
				}).toArray();
			}
			// Process remainder
			function match_part(){
				var m = this.slice(0, parts[i].length),
					p = parts[i].slice(0, m.length);
				return m.toLowerCase() === p.toLowerCase();
			}
			if (parts.length === fparts.length){
				var cnt;
				for (i=0, cnt = fparts.length; i < cnt; i++){
					val = parseInt(parts[i], 10);
					part = fparts[i];
					if (isNaN(val)){
						switch (part){
							case 'MM':
								filtered = $(dates[language].months).filter(match_part);
								val = $.inArray(filtered[0], dates[language].months) + 1;
								break;
							case 'M':
								filtered = $(dates[language].monthsShort).filter(match_part);
								val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
								break;
						}
					}
					parsed[part] = val;
				}
				var _date, s;
				for (i=0; i < setters_order.length; i++){
					s = setters_order[i];
					if (s in parsed && !isNaN(parsed[s])){
						_date = new Date(date);
						setters_map[s](_date, parsed[s]);
						if (!isNaN(_date))
							date = _date;
					}
				}
			}
			return date;
		},
		formatDate: function(date, format, language){
			if (!date)
				return '';
			if (typeof format === 'string')
				format = DPGlobal.parseFormat(format);
			if (format.toDisplay)
                return format.toDisplay(date, format, language);
            var val = {
				d: date.getUTCDate(),
				D: dates[language].daysShort[date.getUTCDay()],
				DD: dates[language].days[date.getUTCDay()],
				m: date.getUTCMonth() + 1,
				M: dates[language].monthsShort[date.getUTCMonth()],
				MM: dates[language].months[date.getUTCMonth()],
				yy: date.getUTCFullYear().toString().substring(2),
				yyyy: date.getUTCFullYear()
			};
			val.dd = (val.d < 10 ? '0' : '') + val.d;
			val.mm = (val.m < 10 ? '0' : '') + val.m;
			date = [];
			var seps = $.extend([], format.separators);
			for (var i=0, cnt = format.parts.length; i <= cnt; i++){
				if (seps.length)
					date.push(seps.shift());
				date.push(val[format.parts[i]]);
			}
			return date.join('');
		},
		headTemplate: '<thead>'+
			              '<tr>'+
			                '<th colspan="7" class="datepicker-title"></th>'+
			              '</tr>'+
							'<tr>'+
								'<th class="prev">&laquo;</th>'+
								'<th colspan="5" class="datepicker-switch"></th>'+
								'<th class="next">&raquo;</th>'+
							'</tr>'+
						'</thead>',
		contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
		footTemplate: '<tfoot>'+
							'<tr>'+
								'<th colspan="7" class="today"></th>'+
							'</tr>'+
							'<tr>'+
								'<th colspan="7" class="clear"></th>'+
							'</tr>'+
						'</tfoot>'
	};
	DPGlobal.template = '<div class="datepicker">'+
							'<div class="datepicker-days">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									'<tbody></tbody>'+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
							'<div class="datepicker-months">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									DPGlobal.contTemplate+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
							'<div class="datepicker-years">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									DPGlobal.contTemplate+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
							'<div class="datepicker-decades">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									DPGlobal.contTemplate+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
							'<div class="datepicker-centuries">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									DPGlobal.contTemplate+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
						'</div>';

	$.fn.datepicker.DPGlobal = DPGlobal;


	/* DATEPICKER NO CONFLICT
	* =================== */

	$.fn.datepicker.noConflict = function(){
		$.fn.datepicker = old;
		return this;
	};

	/* DATEPICKER VERSION
	 * =================== */
	$.fn.datepicker.version = '1.7.0-dev';

	/* DATEPICKER DATA-API
	* ================== */

	$(document).on(
		'focus.datepicker.data-api click.datepicker.data-api',
		'[data-provide="datepicker"]',
		function(e){
			var $this = $(this);
			if ($this.data('datepicker'))
				return;
			e.preventDefault();
			// component click requires us to explicitly show it
			datepickerPlugin.call($this, 'show');
		}
	);
	$(function(){
		datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
	});

}));
;
/******* Modules *******
************************/
window['firstRender'] = true;
let trackFilterTabClicks = {
    previousFilterTabs: []
};
$.fn.datepicker.dates['en']['daysMin'] = ["S", "M", "T", "W", "T", "F", "S"];
function formatNumberWithCommas(x) {
    if (!isNaN(x))
        return parseFloat(x).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    return x;
}
//Get dropdown selected option by dropdown id
function GetSelectedOptionText(id) {
    var $op = $("#" + id + " option:selected");
    return $op.length ? $op.text().trim() : "USD";
}
//Get selected currency text (example value: 'USD')
function GetSelectedCurrency() {
    return GetSelectedOptionText("ddl_Currencies");
}
//Get selected currency symbol (example value: '$')
function GetSelectedCurrencySymbol(notHTML) {
    var Currency = GetSelectedCurrency();
    return Currency == "USD" ?
        (notHTML ? "$" : "&#36;") : (Currency == "EUR" ?
            (notHTML ? "€" : "&#128;") : (notHTML ? "£" : "&#163;"));
}
function kFormatter(num, showPrefix, toFixedNum, isFormatCommas, notHTML) {
    var prefix = GetSelectedCurrencySymbol(notHTML);
    if (num) {
        var suffix = (num > 9999999999 ? 'M' : '');
        var numDiv = suffix == 'M' ? 1000000 : 1;
        toFixedNum = toFixedNum != null ? toFixedNum : 1;
        if (showPrefix) {
            if (isFormatCommas)
                return (prefix) + (num > 999 ? (formatNumberWithCommas(num / numDiv) + suffix) : num);
            return (prefix) + (num > 999 ? ((num / numDiv).toFixed(toFixedNum) + suffix) : num);
        }
        if (isFormatCommas)
            return (num > 9999 ? formatNumberWithCommas(num / numDiv) + suffix : num);
        return (num > 9999 ? (num / numDiv).toFixed(toFixedNum) + suffix : num);
    }
    if (showPrefix) {
        if (checkNested(MA, "CurrentAnalyticsHubModule", "GetSelectedCurrencySymbol"))
            prefix = MA["CurrentAnalyticsHubModule"]["GetSelectedCurrencySymbol"]();
        return "{0}{1}".format(prefix, 0);
    }
    return num;
}
function onOutsideLotFilterClick(e) {
    if ($("body").hasClass("filters-active") &&
        !$(e.target).hasClass(".open-filters") &&
        !$(e.target).parents(".datepicker").length &&
        $(e.target).parents(".mobile-filters-container, .open-filters").length === 0) {
        UncheckDefaultPreferences();
        manager.loadQuery();
        closeFilterBoxSize();
        manager.ToggleFilterControls(false);
        /*onFilterDoneClick(e);*/
    }
}

function checkNested(obj /*, level1, level2, ... levelN*/) {
    var args = Array.prototype.slice.call(arguments, 1);

    for (var i = 0; i < args.length; i++) {
        if (!obj || !obj.hasOwnProperty(args[i])) {
            return false;
        }
        obj = obj[args[i]];
    }
    return true;
}

function iModule(elem) {
    var that = this; // reference

    // properties
    this._elem = $(elem);
    this._queryName = null;
    this._isDisabled = false;
    this._showOnTags = true;
    this._sendEmptyValue = false;
    this._ignoreCount = false;
    this._typeName = null;
    this.isDefault = true;
    this._overrideRefreshcommand = false;

    // public methods
    this.equal = equal;
    this.hide = hide;
    this.isPopulated = isPopulated;
    this.formatFilterText = formatFilterText;
    this.setClearActive = setClearActive;
    this.initCompleted = initCompleted;
    // initialization
    (function () {
        that._elem.parents(".collapsable-title").find(".filter-title span.clear").on("click", function (e) {
            that.setSelected([]);
            e.stopPropagation();
            manager.setQuery();
            var action = that._elem.attr('data-action');
            if (action) eval(action)(that, $(this).data("value"));
            that.setClearActive(false);
            if ($(".mobile-results-controls").length > 0) {
                if (!window['COMS'] || window['COMS'].ViewMode() == "collection-grid")
                    refreshResult(null, window['onLoadMasonryImages']);
            }
        });

        that._queryName = that._elem.attr('data-query-name') || null;
        that._showOnTags = that._elem.attr("data-tag-show") == "True" ? true : false;
        that._sendEmptyValue = that._elem.data("send-empty") == "True";
        that._ignoreCount = that._elem.data("ignore") == "True";
        that._overrideRefreshcommand = that._elem.data("override-refreshcommand");
        that._saveFilteredTextInQuery = that._elem.data('save-filtered-text-in-query') ? that._elem.data('save-filtered-text-in-query').toLowerCase() === 'true' : false;
        that.filterOnChange = false;;

        var isDisabled = that._elem.attr('data-disabled');
        if (isDisabled)
            that._isDisabled = isDisabled == '1';
    })();

    // methods
    function equal(other) {
        // isEqualNode
        return that._elem[0] === other;
    }

    function hide() {
        that._elem.hide(1000);
    }

    function setClearActive(active) {
        that._elem.parents(".collapsable-title").find(".filter-title span.clear")[active ? "addClass" : "removeClass"]("active");
    }

    function initCompleted() {
        that.setClearActive(that.isPopulated());
    }

    // abstract methods
    function setSelected(data) { throw new Error("Not implemented."); }
    function getSelected() { throw new Error("Not implemented."); }
    function isPopulated() { throw new Error("Not implemented."); }
    function formatFilterText(title, data) {
        if (!title || !data)
            return null;;
        if (data instanceof Array || data instanceof Object) {
            var dots = data.length > 2 ? ("...(" + data.length + ")") : "";
            var value = data.splice(0, 2).join(", ");
            title = title.toLowerCase();
            title = title.charAt(0).toUpperCase() + title.slice(1);
            return title + ": " + value + dots;
        } else {
            return title + ": " + data;
        }
    }

    return {
        formatFilterText: formatFilterText,
        initCompleted: initCompleted,
        setClearActive: setClearActive
    }
}

function iRangeModule(elem) {
    var that = this; // reference

    var protected = iModule.call(that, elem); // base

    // properties
    this._leftBox = null;
    this._rightBox = null;

    this._typeName = "iRangeModule";

    // public methods
    this.getRange = getRange;

    // initialization
    (function () { })();

    // methods
    function getRange() {
        var invalidClass = 'invalid';

        if (!Validate()) {
            this._leftBox.addClass(invalidClass);
            this._rightBox.addClass(invalidClass);
            return null;
        }

        this._leftBox.removeClass(invalidClass);
        this._rightBox.removeClass(invalidClass);
        return {
            min: that._leftBox.attr("data-ui-picker") != null ? that._leftBox.datepicker('getDate') : that._leftBox.val(),
            max: that._rightBox.attr("data-ui-picker") != null ? that._rightBox.datepicker('getDate') : that._rightBox.val()
        };
    };

    function Validate() {
        var min = that._leftBox.val();
        var max = that._rightBox.val();
        maxVal = that._rightBox.attr("data-ui-picker") != null ? new Date(max) : parseInt(max);
        minVal = that._leftBox.attr("data-ui-picker") != null ? new Date(min) : parseInt(min);

        if (min != '' && max != '')
            return maxVal >= minVal;
        return true;
    }

    // protected
    return {
        bindAction: function (eventName, selector, action) {
            that._elem.on(eventName, selector, function (x) {
                eval(action)(that)
                that.setClearActive(that.isPopulated());
            });
        },
        bindBoxesOnlyNumbersAction: function () {
            that._elem.on('keydown', 'input[type = "number"]', function (e) {
                var keyCode = (e.keyCode > 0) ? e.keyCode : e.charCode;

                // between 0 - 9  or left/right arrows
                var isAllowed = ((keyCode >= 48 && keyCode <= 57) || (e.keyCode >= 96 && e.keyCode <= 105) || e.keyCode >= 110 || e.keyCode <= 190 || keyCode == 37 || keyCode == 39 || keyCode == 8);
                /// console.log(keyCode + ': ' + isAllowed);

                if (!isAllowed) {
                    e.preventDefault();
                    return false;
                }
            });
        },
        formatFilterText: protected.formatFilterText,
        initCompleted: protected.initCompleted,
        typeName: "iRangeModule",
        validate: Validate
    };
}

dateRangeModule.prototype = Object.create(iRangeModule.prototype);
numericRangeModule.prototype = Object.create(iRangeModule.prototype);

function iDropdownModule(elem) {
    var that = this;

    iModule.call(that, elem);

    //init
    (function () {
    })();

    return {
        bindAction: function (eventName, selector, action, callback, preinit) {
            that._elem.on(eventName, selector, function (x) {
                if (preinit) preinit.call(null, x);
                eval(action)(that, x.target);
                if (callback) callback.call(null, x);
                x.stopPropagation();
                that.setClearActive(that.isPopulated());
            });
        },

        initCompleted: function () {
            var initProvider = that._elem.attr('data-init-provider');
            if (initProvider)
                eval(initProvider)(that);

            if (that._isDisabled)
                that.disableItems();

            that.setClearActive(that.isPopulated());
        }
    }
}

function iListModule(elem) {
    var that = this; // reference

    var protected = iModule.call(that, elem); // base

    // properties
    this._list = null;
    this._EmptyIfNoPhrase = true;

    // public methods
    this.clearItems = clearItems;
    this.hideItems = hideItems;
    this.showItems = showItems;
    this.disableItems = disableItems;
    this.getItems = getItems;
    this.clearSelected = clearSelected;
    this.findInput = findInput;
    this.initScrollbar = initScrollbar;
    this.bindItems = bindItems;
    this.getSelectedIds = getSelectedIds;
    this.countSelected = countSelected;
    this.delayedExecution;

    // initialization
    (function () {
        // ul (_list) is not exists - add it
        var ulExists = that._elem.find('> ul').length > 0;
        that._list = ulExists ? that._elem.find('> ul:first') : $('<ul />');
        that._elem.append(that._list);

        that.allowCreate = that._elem.data('create');
        that.CreateEventName = that._elem.data('create-name');
        that.CapitalizeCreate = that._elem.data('create-capitalize');

        var dfr_attr = that._elem.attr("data-focus-results")
        that.focusResults = typeof dfr_attr !== typeof undefined && dfr_attr !== false;

        that.initScrollbar();

        var listHeight = that._elem.attr('data-list-height');
        if (listHeight) that._list.css('max-height', listHeight);

        var emptyIfNoPhrase = that._elem.attr('data-empty-list-if-no-phrase');
        if (emptyIfNoPhrase)
            that._EmptyIfNoPhrase = emptyIfNoPhrase == '1';
    })();

    // methods
    function clearItems(theList) {
        theList = theList || that._list;
        theList.empty();
    }

    function hideItems(theList) {
        theList = theList || that._list;
        theList.find('li').hide();
    }

    function showItems(theList) {
        theList = theList || that._list;
        theList.find('li').show();
    }

    function disableItems(theList) {
        theList = theList || that._list;
        theList.find('li input').prop('disabled', 'disabled');
        theList.find('li label').addClass('disabled',);
    }

    function clearSelected(theList) {
        theList = theList || that._list;
        theList.find('input').removeAttr('checked');
    }

    function clearItems(theList) {
        theList = theList || that._list;
        theList.empty();
    }

    function findInput(value, theList) {
        theList = theList || that._list;
        return theList.find('li input[value="' + value + '"]:first');
    }

    function initScrollbar(theList) {
        theList = theList || that._list;
        theList.addClass('module-scrollbar');
    }

    // abstract methods
    function getItems() { throw new Error("Not implemented."); }
    function bindItems(data) { throw new Error("Not implemented."); }
    function getSelectedIds() { throw new Error("Not implemented."); };
    function countSelected() { throw new Error("Not implemented."); }
    function GetSelectedTexts() { throw new Error("Not implemented."); }
    function searchByValue() { throw new Error("Not implemented."); }
    function getTextForFilter() { throw new Error("Not implemented."); }
    function getValueFormat() { throw new Error("Not implemented."); }

    function executeSearch(theList, provider, that, x) {
        theList.show();
        eval(provider)(that);
        x.stopPropagation();

        function onBodyClick(e) {
            if ($(e.target).parents("[data-module='autocomplete']").length)
                return false;
            that.clearItems(theList);
        }

        $("body").off("click", onBodyClick);
        $("body").on("click", onBodyClick);
    }

    // protected
    return {
        bindAction: function (eventName, selector, action, callback, preinit) {
            that._elem.on(eventName, selector, function (x) {
                if (preinit) preinit.call(null, x);
                eval(action)(that, x.target);
                if (callback) callback.call(null, x);
                x.stopPropagation();
                that.setClearActive(that.isPopulated());
            });
        },
        bindDataProvider: function (eventName, selector, provider) {
            that._elem.on(eventName, selector, function (x) {
                that._list.show();
                eval(provider)(that);
                x.stopPropagation();
            });
        },

        // TODO ->> [Temporary] move out to an intermediate base class for autocomplete
        bindDataProviderUsingAutocomplete: function (eventName, selector, provider, theList, emptyValueCallback) {
            theList = theList || that._list;
            that._elem.unbind(eventName);
            that._elem.on(eventName, selector, function (x) {
                clearTimeout(that.delayedExecution);
                var phrase = that.getSearchPhrase().trim();
                var phraseCount = phrase.length;

                that.setClearActive(that.isPopulated());
                if ((x.type == "keyup" && (phraseCount == 0 || x.keyCode == 13)) || (!that.focusResults && phraseCount > 0 && phraseCount < 2 && phrase != "*")) return;
                // empty search value - clear items and don't trigger the event!
                if (!that.focusResults && that._EmptyIfNoPhrase && phraseCount == 0 && phrase != "*") {
                    that.clearItems(theList);

                    if (emptyValueCallback) emptyValueCallback.call(null, x);
                    return;
                }
                that.delayedExecution = setTimeout(executeSearch.bind(this, theList, provider, that, x), phrase != "*" ? 200 : 0);
            });
        },
        formatFilterText: protected.formatFilterText,
        protected: protected,
        initCompleted: function () {
            var initProvider = that._elem.attr('data-init-provider');
            if (initProvider)
                eval(initProvider)(that);

            if (that._isDisabled)
                that.disableItems();

            protected.initCompleted();
        }
    }
}

iRangeModule.prototype = Object.create(iModule.prototype);
iListModule.prototype = Object.create(iModule.prototype);
// [ISSUE] DO NOT use new iListModule -> issue with instanceof clause
freeSearchModule.prototype = Object.create(iModule.prototype);
autoCompleteModule.prototype = Object.create(iListModule.prototype);
checklistModule.prototype = Object.create(iListModule.prototype);
taglistAutoCompleteModule.prototype = Object.create(iListModule.prototype);
checklistAutoCompleteModule.prototype = Object.create(iListModule.prototype);
radiolistAutoCompleteModule.prototype = Object.create(iListModule.prototype);
radiolistModule.prototype = Object.create(iListModule.prototype);
checklistAddToListModule.prototype = Object.create(iListModule.prototype);
dropdownModule.prototype = Object.create(iListModule.prototype);
tagsModule.prototype = Object.create(iListModule.prototype);
periodSwitcherModule.prototype = Object.create(iModule.prototype);
badgesFilterModule.prototype = Object.create(iModule.prototype);
sizeFilterModule.prototype = Object.create(iModule.prototype);
orientationFilterModule.prototype = Object.create(iModule.prototype);

// [module] freeSearchModule
function freeSearchModule(elem) {
    var that = this; // reference

    var protected = iListModule.call(that, elem); // base

    // properties
    this._phraseInput = null;

    // override methods
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.getSelectedIds = getSelected;
    this.isPopulated = isPopulated;
    // public methods
    this.getSelectedTexts = getSelectedTexts;
    this.getSearchPhrase = getSearchPhrase;
    this.removeSelected = removeSelected;
    this.renderSelectedBedges = renderSelectedBedges;
    this.clearSelected = removeSelected;

    // initialization
    (function (protected) {
        that._elem.addClass('freeSearch-module');

        that._phraseInput = that._elem.find('input[type="text"]:eq(0)');
        that._searchBtn = that._elem.find("button.search-btn");
        var action = that._elem.attr('data-action');
        if (that._searchBtn.length) {
            that._phraseInput.on("keyup", function (e) {
                protected.protected.setClearActive(isPopulated());
                if (that._phraseInput.val().length > 0) {
                    that._searchBtn.addClass("active");
                    if (e.keyCode == 13) {
                        that._searchBtn.click();
                        //onDoneClick();
                    }
                }
                else {
                    that._searchBtn.removeClass("active");
                    if (action && !$(".mobile-results-controls.open").length)
                        eval(action)(that, null);
                    //that._searchBtn.click();
                }
            });
            if (action)
                protected.bindAction('click', that._searchBtn, function (t, x) {
                    if (x.nodeName == "BUTTON" || x.parentElement.nodeName == "BUTTON") {
                        eval(action)(t, x);
                        onFilterDoneClick();
                    }
                });
        } else if (action) {
            protected.bindAction('change', that._phraseInput, action);
        };
        protected.initCompleted(); // after fully loaded!
    })(protected);

    // methods
    function setSelected(data) {
        if (!data || !data.length) {
            that._phraseInput.val('');
            that._phraseInput.trigger('keyup');
        }
        else
            that._phraseInput.val(data[0] || '');
    }

    function removeSelected() {
        that._phraseInput.val('');
    }

    function getSelected() {
        return [that.getSearchPhrase()];
    }

    function isPopulated() {
        return that.getSearchPhrase() != '';
    }

    function getSearchPhrase() {
        return that._phraseInput.val().trim();
    }

    function getSelectedTexts() {
        return [getSearchPhrase()];
    }

    function renderSelectedBedges(parentEle) {
        var selectedFilterTexts = that.getSelected();
        $.each(selectedFilterTexts, function (key, value) {
            createBedge(value, that._queryName, value, parentEle);
        });
    }
}

// [module] periodSwitcher
function periodSwitcherModule(elem) {
    var that = this;

    var protected = iModule.call(that, elem); // base

    // initialization

    // override methods
    this.getItems = getItems;
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.countSelected = countSelected;
    this.getSelectedTexts = getSelectedTexts;

    (function (protected) {
        that._elem.addClass('period-switcher-module');

        var action = that._elem.attr('data-action');

        that._elem.on('click', 'ul > li > a', function () {
            that.setSelected($(this).data("value"));
            if (action) eval(action)(that, $(this).data("value"));
        });
        if (getParameterByName(that._queryName))
            that.setSelected(getParameterByName(that._queryName));
        //protected.initCompleted(); // after fully loaded!
    })(protected);

    // methods
    function getItems() {
        var items = that._list.find('a');
        return items.toArray().map(function (x) {
            return {
                value: $(x).data("value"),
                text: $(x).text().trim()
            }
        });
    }

    function getSelectedTexts() {
        return null;
    }

    function getSelected() {
        return [that._elem.find("a.active").data("value")];
    }

    function isPopulated() {
        return true;
    }

    function setSelected(data) {
        that._elem.find("a").removeClass("active");
        that._elem.find("a[data-value='" + data + "']").addClass("active");
    }

    function countSelected() {
        return 1;
    }
}
// [module] tagsModule
function tagsModule(elem) {
    var that = this;

    var protected = iListModule.call(that, elem); // base

    // override methods
    this.getItems = getItems;
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    //this.bindItems = bindItems;
    //this.getSelectedIds = getSelectedIds;
    this.countSelected = countSelected;
    this.bindData = bindData;
    this.autoShowHide = autoShowHide;

    // initialization
    (function (protected) {
        that._elem.addClass('tags-module');

        var action = that._elem.attr('data-action');
        var moveSize = 200;
        that._elem.parent().find(".tags-navigation > a").on("click", function () {
            var $navButton = $(this);
            var isRight = $(this).hasClass("move-right");
            var leftPos = that._elem.scrollLeft();
            if (isRight) {
                that._elem.animate({
                    scrollLeft: leftPos + moveSize
                }, 200, null, function () {
                    $(".tags-navigation > a").removeClass("hidden");
                    if (leftPos + moveSize > that._elem.scrollLeft()) {
                        $navButton.addClass("hidden");
                    }
                });
            } else {
                that._elem.animate({
                    scrollLeft: leftPos - moveSize
                }, 200, null, function () {
                    $(".tags-navigation > a").removeClass("hidden");
                    if (that._elem.scrollLeft() < 1) {
                        $navButton.addClass("hidden");
                    }
                });
            }
        });
        $(window).off("resize", onResize);
        $(window).on("resize", onResize);
        onResize();
        //that._elem.on('click', 'ul > li > a.close', function () {
        //    $(this).parent().remove();
        //    if (action) eval(action)(that, $(this).data("value"));
        //});

        that.bindData();

        protected.initCompleted(); // after fully loaded!
    })(protected);

    // methods
    function getItems() {
        var modules = manager.modules();
        var tagData = [];
        for (var i in modules) {
            var mod = modules[i];
            if (!mod._showOnTags || mod.getSelectedTexts === undefined) { //Range
                continue;
            }
            var val = mod.getSelected();
            val = val == '-' ? null : val;
            var textValue = mod.getSelectedTexts();
            if (textValue != null && textValue != '') {
                if ((textValue instanceof Array)) {
                    for (var index in textValue) {
                        tagData.push({
                            query: mod._queryName,
                            value: val[index],
                            txt: textValue[index]
                        });
                    }
                } else {
                    tagData.push({
                        query: mod._queryName,
                        value: val,
                        txt: mod._typeName == 'iRangeModule' ? mod.getTextForFilter() : textValue
                    });
                }
            }
        }
        autoShowHide();

        return tagData;
    }

    function autoShowHide() {
        if ($(that._elem).data('auto-show-hide')) {
            if ($(that._elem).find(".tags-list").children().length > 0) {
                $(that._elem).show();
            }
            else {
                $(that._elem).hide();
            }
        }
    }

    function onCloseTag() {
        manager.removeQuery($(this).data("query"), $(this).data("value"));
        //manager.setQuery();
        $(this).parent().remove();
        onFilterDoneClick();
        autoShowHide();
        //var action = that._elem.attr('data-action');
        //if (action) eval(action)(that, $(this).data("value"));
    }

    function bindData() {
        var data = that.getItems();

        var html = '';
        for (var index in data) {
            var tag = data[index];
            //html += '<li style="cursor:pointer;">' + tag.txt + '<a data-query="' + tag.query + '" data-value="' + tag.value + '" class="close">&times;</a></li>';
            html += `
                <div class="btn-group margin-bottom-10" data-val="${tag.value}" data-tag-type="${tag.query}">
                  <button type="button" class="btn btn-gray btn-pill btn-bubble btn-select-bubble">${tag.txt}</button>
                  <button type="button" class="btn btn-gray btn-pill btn-bubble btn-remove-bubble"><i class="m-icon-menu-close bold"></i></a></button>
                </div>
            `;
        }

        that._elem.find("ul").html(html);
        autoShowHide();
        that._elem.off("click", "ul > li > a.close", onCloseTag);
        that._elem.on("click", "ul > li > a.close", onCloseTag);
        that._elem.on("click", "ul > li", function (e) {
            if (e && !$(e.target).is('a.close')) {
                var q_name = $(this).children().data('query');
                var selectedModule = manager.getModulesByQueryString(q_name);
                if (selectedModule && selectedModule.length > 0) {
                    closeFilterBoxSize();
                    if (selectedModule[0]._elem.closest('.collapsable-title').length > 0) {
                        selectedModule[0]._elem.closest('.collapsable-title').removeClass('collapsed');
                        SetCardSize();
                        manager.ToggleFilterControls(true);
                    }
                }
            }
        });
    }

    function getSelected() {
        return [that._elem.find("li")];
    }

    function isPopulated() {
        return true;
    }

    function setSelected(data) {
        that._elem.find("a").removeClass("active");
        $(data).addClass("active");
    }

    function countSelected() {
        return that._elem.find("li").count;
    }

    function onResize() {
        var element = that._elem.get(0);
        if (element.offsetHeight < element.scrollHeight ||
            element.offsetWidth < element.scrollWidth) {
            that._elem.parent().removeClass("hide-nav");
            if (that._elem.scrollLeft() < 1) {
                that._elem.parent().find(".move-left").addClass("hidden");
                that._elem.parent().find(".move-right").removeClass("hidden");
            }
        } else {
            that._elem.parent().addClass("hide-nav");
        }
    }
}

// [module] dropdownModule
function dropdownModule(elem) {
    var that = this; // reference
    var protected = iDropdownModule.call(that, elem); // base

    // override methods
    this.getItems = getItems;
    this.bindItems = bindItems;
    this.isPopulated = isPopulated;
    this.getSelected = getSelected;
    this.getSelectedIds = getSelected;
    this.setSelected = setSelected;
    this.getSelectedTexts = getSelectedTexts;
    this.getSelectedLabel = getSelectedLabel;
    this.getTextForFilter = getTextForFilter;
    this.removeSelected = removeSelected;
    this.renderSelectedBedges = renderSelectedBedges;
    this.clearSelected = removeSelected;
    // public methods

    // initialization
    (function (protected) {
        that._elem.addClass('dropdown-module');
        that.defaultValue = that._elem.attr("data-initial-value")

        var action = that._elem.attr('data-action');

        var defaults = {
            height: 33,
            selectedMarker: "",
            customClass: "filter-dropdown arrow"
        };
        var options = that._elem.data("options");
        if (!options) {
            options = defaults;
        }
        that.$prettyDropDown = that._elem.find("select").prettyDropdown(options);

        that._elem.off('change');
        that._elem.on('change', 'select', function () {
            if (action) eval(action)(that, $(this).val());            
        });

        protected.initCompleted(); // after fully loaded!
    })(protected);

    // methods
    function getItems() {
        var items = that._list.find('option');
        return items.toArray().map(function (x) {
            return {
                value: $(x).val(),
                text: $(x).text().trim()
            }
        });
    }

    function bindItems(data) {
        that.clearItems();
        if (!(data instanceof Array))
            return;
        for (i in data)
            that._list.append('<option>' + data[i] + '</option>');
    }

    function getSelected() {
        var v = that._elem.find("select").val();
        if (that.defaultValue && v == that.defaultValue)
            return [];
        return [v];
    }

    function getSelectedTexts() {
        var label = getSelectedLabel();
        return [label];
    }

    function isPopulated() {
        return true;
    }

    function setSelected(data) {
        if (data != null && data instanceof Array)
            data = data[0];

        if (!getParameterByName(that._queryName) && data)
            that._elem.find("select").val(data);
        else if (getParameterByName(that._queryName))
            that._elem.find("select").val(getParameterByName(that._queryName));
        else if (that.defaultValue) {
            that._elem.find("select").val(that.defaultValue);
        }
        that.$prettyDropDown.refresh();
    }

    function removeSelected() {
        that._elem.find("select").val(that.defaultValue);
        that.$prettyDropDown.refresh();
    }

    function getSelectedLabel() {
        return that._elem.find("select option:selected").text().trim();
    }

    function getTextForFilter() {
        return that._queryName + ' : ' + that._elem.find("select option:selected").text().trim();
    }

    function renderSelectedBedges(parentEle) {
        var selectedFilterText = that.getSelectedLabel();
        var selectedFilterIds = that.getSelectedIds();
        $.each(selectedFilterIds, function (key, value) {
            if (!['artworkSort', 'groupBy', 'valuationSort', 'Currency'].includes(that._queryName)) {
                createBedge(selectedFilterIds[key], that._queryName, selectedFilterText, parentEle);
            }
        });
        that.$prettyDropDown.refresh();
    }
}

// [module dateRangeModule]
// [module] numericRangeModule
function dateRangeModule(elem) {
    var that = this; // reference

    var protected = iRangeModule.call(that, elem); // base

    //properties
    this._isMobile = false;

    // override methodsgetSelected
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.getSelectedTexts = getSelectedTexts;
    this.getTextForFilter = getTextForFilter;
    this.getValueFormat = getValueFormat;
    this.removeSelected = removeSelected;
    this.renderSelectedBedges = renderSelectedBedges;
    this.clearSelected = removeSelected;
    // initialization
    (function (protected) {
        that._elem.addClass('date-range-module');
        that._clear = that._elem.find("[data-clear]");
        that._isMobile = that._elem.hasClass("mobile");

        that._leftBox = that._elem.find('input:eq(0)');
        that._rightBox = that._elem.find('input:eq(1)');
        if ($('.filter-section').length > 0) {
            that._leftBox.attr('type', 'text');
            that._rightBox.attr('type', 'text');
            that._leftBox.attr('data-ui-picker', '');
            that._rightBox.attr('data-ui-picker', '');
        }

        if (that._isMobile && $(that._leftBox).attr('type') == 'date') {
            that._elem.on("click", function (e) {
                $(".datepicker").hide();
            })

            that._elem.find("input[type='date']").on("change", function (e) {
                if (this.value && this.value.length) {
                    let temp = $.datepicker.formatDate(this.getAttribute("data-date-format"), new Date(this.value));
                    this.setAttribute("data-date", temp);
                    that._elem.parents(".collapsable-title").find(".filter-title span.clear").addClass('active');
                } else
                    this.setAttribute("data-date", "");

                if (new Date(that._leftBox[0].value) > new Date(that._rightBox[0].value)) {
                    let incdate = new Date(that._leftBox[0].value);
                    incdate.setDate(incdate.getDate() + 1);
                    that._rightBox[0].setAttribute("data-date", $.datepicker.formatDate(that._rightBox[0].getAttribute("data-date-format"), incdate));
                }

                var action = that._elem.attr('data-action');
                if (action) {
                    that.action = action;
                    eval(that.action)(null, e);
                }
            });

            that._clear.on('click', function (e) {
                setSelected(null);
            });
        } else {
            that._leftBox = that._elem.find('input[data-date-format]:eq(0)').datepicker({
                autoclose: true,
                templates: {
                    leftArrow: '&nbsp;',
                    rightArrow: '&nbsp;'
                },
                orientation: 'bottom'
            }).datepicker('clearDates');
            that._rightBox = that._elem.find('input[data-date-format]:eq(1)').datepicker({
                autoclose: true,
                templates: {
                    leftArrow: '&nbsp;',
                    rightArrow: '&nbsp;'
                },
                orientation: 'bottom'
            }).datepicker('clearDates');

            that._clear.on('click', function (e) {
                that._leftBox.datepicker('clearDates');
                that._rightBox.datepicker('clearDates');
            });

            var action = that._elem.attr('data-action');
            if (action) {
                that.action = action;
                protected.bindAction('change', 'input', ActionValidator);
            }
        }

        protected.initCompleted();
    })(protected);

    function ActionValidator(e) {
        if (that._rightBox.val().length && that._leftBox.datepicker('getDate') > that._rightBox.datepicker('getDate')) {
            that._rightBox.datepicker('setDate', that._leftBox.datepicker('getDate').addDays(1));
        } else {
            eval(that.action)(that, e);
        }
    }

    // methods
    function setSelected(data) {
        if (data == null || data.length == 0) {
            that._leftBox.datepicker("setDate", null);
            that._rightBox.datepicker("setDate", null);
            return;
        }
        if (!(data instanceof Array))
            return;
        if (that._isMobile && $(that._leftBox).attr('type') == 'date') {
            if (data[0].length)
                that._leftBox.val(data[0]).trigger("change");
            if (data[1].length)
                that._rightBox.val(data[1]).trigger("change");
        }
        else {
            if (data[0].length)
                that._leftBox.datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', data[0]));
            if (data[1].length)
                that._rightBox.datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', data[1]));
        }
    }

    function getSelected() {
        var range = that.getRange();
        var min = "", max = "";
        if (range != null) {
            if (range.min)
                min = that._isMobile && $(that._leftBox).attr('type') == 'date' ? range.min : $.datepicker.formatDate('yy-mm-dd', range.min);
            if (range.max)
                max = that._isMobile && $(that._leftBox).attr('type') == 'date' ? range.max : $.datepicker.formatDate('yy-mm-dd', range.max);
        }
        return [''.concat(min, '_', max)];
    }

    function removeSelected() {
        that._leftBox.datepicker("setDate", null);
        that._rightBox.datepicker("setDate", null);
    }

    function isPopulated() {
        var range = that.getRange();
        var min = "", max = "";
        if (range != null) {
            if (range.min)
                min = range.min
            if (range.max)
                max = range.max
        }
        return min != '' || max != '';
    }

    function getSelectedTexts() {
        var range = that.getRange();
        var fText = that._elem.parents(".filter-group").find(".filter-header > span").text() || that._elem.parents(".collapsable-title").find("span.filter-title span.title:first").text().trim() || '';
        if (fText)
            fText = fText + ": ";
        return fText + getValueFormat();
        return null;
    }

    function getTextForFilter() {
        if (that._elem.parents(".collapsable-title").length) {
            return protected.formatFilterText(that._elem.parents(".collapsable-title").find("span.filter-title span.title:first").text().trim(), getValueFormat());
        }
        return null;
    }
    function getValueFormat() {
        var range = that.getRange();
        if (!range.min && range.max)
            return "Up to " + $.datepicker.formatDate('yy-mm-dd', range.max);
        if (!range.max && range.min)
            return "From " + $.datepicker.formatDate('yy-mm-dd', range.min);

        return range.max && range.min ? ("Between " + $.datepicker.formatDate('yy-mm-dd', range.min)
            + " and "
            + $.datepicker.formatDate('yy-mm-dd', range.max)) : null;
    }

    function renderSelectedBedges(parentEle) {
        var selectedFilterTexts = that.getSelected();
        $.each(selectedFilterTexts, function (key, value) {
            createBedge(value, that._queryName, that.getSelectedTexts(), parentEle);
        });
    }
}

// [module] numericRangeModule
function numericRangeModule(elem) {
    var that = this; // reference
    that.stepsCount = IsMobileView() || $('body').hasClass('mobile-always-filter') ? 3 : 5;
    var protected = iRangeModule.call(that, elem); // base

    //properties
    this.TagFormat = false;
    this.IsCM = null;
    this._range_slider = null;

    // override methods
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.getSelectedTexts = getSelectedTexts;
    this.getSelectedIds = getSelectedTexts;
    this.getTextForFilter = getTextForFilter;
    this.getValueFormat = getValueFormat;
    this.removeSelected = removeSelected;
    this.renderSelectedBedges = renderSelectedBedges;
    this.clearSelected = removeSelected;
    this.setSlider = setSlider;
    this.setSliderMaxRange = setSliderMaxRange;
    // initialization
    (function (protected) {
        that._elem.addClass('numeric-range-module-block');

        that.TagFormat = that._elem.data("tag-format") == true;

        that._leftBox = that._elem.find('input[type="number"]:eq(0)');
        that._rightBox = that._elem.find('input[type="number"]:eq(1)');

        that._leftBox.on('keyup change', that.setSlider);
        that._rightBox.on('keyup change', that.setSlider);

        protected.bindBoxesOnlyNumbersAction();

        var action = that._elem.attr('data-action');
        var linkText = that._elem.find(".link-text");
        if (action) {
            //protected.bindAction('change', 'input[type="number"]', action);
            protected.bindAction('click', 'button.numeric-range-apply-btn[type="button"]', action);
            that.action = action;
        }

        //if (that._elem.prev().children(".range-slider").length > 0) {
        //    that._range_slider = that._elem.prev().children(".range-slider")
        //        .slider({
        //            min: 0,
        //            max: 100,
        //            step: 1,
        //            range: true,
        //            values: [0, 0],
        //            slide: function (event, ui) {
        //                that._leftBox.val(ui.values[0]);
        //                that._rightBox.val(ui.values[1]);
        //            }
        //        });

        //    that.setSliderMaxRange();
        //    that.setSlider();
        //}

        if ($('body').hasClass('mobile-always-filter')) {
            that._elem.addClass('w-100');
        }
    })(protected);

    // methods
    function validateRange() {
        var invalidClass = 'invalid';

        if (!protected.validate()) {
            that._leftBox.addClass(invalidClass);
            that._rightBox.addClass(invalidClass);
            that._elem.closest('.filters-card').find('.action-done').css('pointer-events', 'none');
        } else {
            that._leftBox.removeClass(invalidClass);
            that._rightBox.removeClass(invalidClass);
            if (that._elem.closest('.sale-outcome').find('.numeric-range-module-block input.invalid').length > 0) {
                that._elem.closest('.filters-card').find('.action-done').css('pointer-events', 'none');
                return;
            }
            that._elem.closest('.filters-card').find('.action-done').css('pointer-events', 'auto');
        }
    }

    function setSelected(data) {
        if (!(data instanceof Array)) {
            that._leftBox.val('');
            that._rightBox.val('');
            that._leftBox.removeClass('invalid');
            that._rightBox.removeClass('invalid');

            if (that._queryName === 'width') {
                that._elem.closest('.filters-card-body-container').find('.artwork-size-option').removeClass('selected');
            }
        } else if (data == null || data.length == 0) {
            that._leftBox.val('');
            that._rightBox.val('');
            that._leftBox.removeClass('invalid');
            that._rightBox.removeClass('invalid');
        } else {
            var values = data[0].split('-');
            that._leftBox.val(values[0] || '');
            that._rightBox.val(values[1] || '');
        }

        if (that._range_slider) {

            var values = that.getSelected()[0].split('-');
            that._range_slider.slider("values", [values[0] || 0, values[1] || 0]);
            //that.setSliderMaxRange();
            //that.setSlider();
        }
    }

    function removeSelected() {
        that._leftBox.val('');
        that._rightBox.val('');
        if (that._range_slider) {
            that._range_slider.slider("values", [0, 0]);
            //that.setSliderMaxRange();
            //that.setSlider();
        }

        if (that._queryName === 'width') {
            that._elem.closest('.filters-card-body-container').find('.artwork-size-option').removeClass('selected');
    }
    }

    function getSelected() {
        var range = that.getRange();
        var min = "", max = "";
        if (range != null) {
            if (range.min)
                min = range.min
            if (range.max)
                max = range.max
        }
        return [''.concat(min, '-', max)];
    }

    function isPopulated() {
        var range = that.getRange();
        var min = "", max = "";
        if (range != null) {
            if (range.min)
                min = range.min
            if (range.max)
                max = range.max
        }
        return min != '' || max != '';
    }

    function getSelectedTexts() {
        if (that.getSelected() != "-") {
            var range = that.getRange();
            var fText = that._elem.parents(".filter-group").find(".filter-header > span").text() || that._elem.parents(".collapsable-title").find("span.filter-title span.title:first").text().trim() || '';
            if (fText)
                fText = fText + ": ";
            return fText + kFormatter(range.min, that.TagFormat) + " - " + kFormatter(range.max, that.TagFormat);
        }
        return null;
    }

    function getTextForFilter() {
        if (that._elem.parents(".collapsable-title").length) {
            var title = that._elem.closest('.filter-group').find('.filter-header span').eq(0).text();
            return protected.formatFilterText(title ? title : that._elem.parents(".collapsable-title").find("span.filter-title span.title:first").text().trim(), getValueFormat());
        }
        return null;
    }

    function getValueFormat() {
        var yearQueryNames = ['year', 'artworkRange', 'saleYear', 'artworkYear'];
        var range = that.getRange();
        var txt = that.IsCM == null ? (that._elem.find("span.label-unit")[0] ? that._elem.find("span.label-unit")[0].innerText : "") : (that.IsCM === true ? "cm" : "in");
        if (!range.min && range.max)
            return "Up to " + (!yearQueryNames.includes(that._queryName) ? formatNumberWithCommas(range.max) : range.max) + " " + txt;
        if (!range.max && range.min)
            return "From " + (!yearQueryNames.includes(that._queryName) ? formatNumberWithCommas(range.min) : range.min) + " " + txt;

        return range.max && range.min ? ("Between " + (!yearQueryNames.includes(that._queryName) ? formatNumberWithCommas(range.min) : range.min) + (range.min ? " " + txt : "Up to ") + " - " + (!yearQueryNames.includes(that._queryName) ? formatNumberWithCommas(range.max) : range.max) + (range.max ? " " + txt : "")) : null;
    }

    function renderSelectedBedges(parentEle) {
        createBedge(that.getSelectedIds(), that._queryName, that.getTextForFilter(), parentEle);
    }

    function getSliderMaxValue(slider_type) {
        if (slider_type == "height") {
            var max_value = that.IsCM ? _maxArtworkResult.height.height_cm : _maxArtworkResult.height.height_in;
            return max_value > 5000 ? 5000 : max_value;
        }
        else if (slider_type == "width") {
            var max_value = that.IsCM ? _maxArtworkResult.width.width_cm : _maxArtworkResult.width.width_in;
            return max_value > 5000 ? 5000 : max_value;
        }
        else if (slider_type == "price") {
            var badgesEle = $('[data-query-id=' + that._queryName + ']').closest(".filters-card-body").find('.badges-filter-block');
            var selected_currency = badgesEle.find('a.selected').text();
            return (selected_currency == "EUR" ? _maxArtworkResult.price.maxEUR : (selected_currency == "GBP" ? _maxArtworkResult.price.maxGBP : _maxArtworkResult.price.maxUSD));
        }
    }

    function getSliderOptions(minValue, maxValue, slider_type) {
        var steps = 1;
        var visibleStep = 1;
        var sliderMaxValue = getSliderMaxValue(slider_type);
        visibleStep = Math.round(sliderMaxValue / steps / that.stepsCount);
        return { minValue: Math.round(minValue), maxValue: Math.round(maxValue), visibleStep: visibleStep, steps: steps, sliderMaxValue: sliderMaxValue };
    }

    function setSliderOptions(sliderOptions) {
        that._leftBox.attr("step", sliderOptions.steps);
        that._rightBox.attr("step", sliderOptions.steps);
        that._rightBox.attr("max", sliderOptions.sliderMaxValue);

        that._range_slider.on('click', function (e) {
            if ($(e.target).hasClass('ui-slider-label')) {
                var values = that._range_slider.slider("values");
                if (values && jQuery.isArray(values) && values.length > 1) {
                    that._leftBox.val(values[0]);
                    that._rightBox.val(values[1]);
                }
            }
        });

        var slider_type = that._range_slider.attr('data-slider-type');
        if (slider_type == "price") {
            var badgesEle = $('[data-query-id=' + that._queryName + ']').closest(".filters-card-body").find('.badges-filter-block');
            var sign = badgesEle.find('a.selected').attr("data-sign");

            that._range_slider.slider('option', { values: [sliderOptions.minValue, sliderOptions.maxValue], step: sliderOptions.steps }).slider("pips", {
                rest: "label",
                step: sliderOptions.visibleStep,
                prefix: sign,
                formatLabel: function (val) { return this.prefix + priceFormatter(val, 1) }
            });
        } else {
            that._range_slider.slider('option', { values: [sliderOptions.minValue, (sliderOptions.maxValue == 0 ? sliderOptions.sliderMaxValue : sliderOptions.maxValue)], step: sliderOptions.steps }).slider("pips", {
                rest: "label",
                step: sliderOptions.visibleStep,
                suffix: that.IsCM ? " cm" : " in"
            });
        }
    }

    function priceFormatter(num, digits) {
        const lookup = [
            { value: 1, symbol: "" },
            { value: 1e3, symbol: "K" },
            { value: 1e6, symbol: "M" }
        ];
        const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
        var item = lookup.slice().reverse().find(function (item) {
            return num >= item.value;
        });
        return item ? (num / item.value).toFixed(digits).replace(rx, "$1") + item.symbol : "0";
    }

    function setSlider() {
        validateRange();
        if (that._range_slider && protected.validate()) {
            var range = that.getRange();
            var slider_type = that._range_slider.attr('data-slider-type');
            if (range.min == '' && range.max == '') {
                if (slider_type == "height") {
                    setSliderOptions(getSliderOptions(0, getSliderMaxValue(slider_type), slider_type));
                }
                if (slider_type == "width") {
                    setSliderOptions(getSliderOptions(0, getSliderMaxValue(slider_type), slider_type));
                }
                if (slider_type == "price") {
                    that._range_slider.slider("values", [0, getSliderMaxValue(slider_type)]);
                    setSliderOptions(getSliderOptions(0, getSliderMaxValue(slider_type), slider_type));
                }
            } else {
                setSliderOptions(getSliderOptions(parseInt(range.min) || 0, parseInt(range.max) || getSliderMaxValue(slider_type), slider_type));
            }
        }
    }

    function setSliderMaxRange() {
        if (that._range_slider) {
            var slider_bar_1 = that._range_slider.next('.range-slide-bar').find('span:nth-child(1)');
            var slider_bar_2 = that._range_slider.next('.range-slide-bar').find('span:nth-child(2)');
            var slider_type = that._range_slider.attr('data-slider-type');
            if (slider_type == "height") {
                that._range_slider.slider("option", "max", getSliderMaxValue(slider_type));
                slider_bar_1.html('0' + (that.IsCM ? " cm" : " in"));
                slider_bar_2.html(getSliderMaxValue(slider_type) + (that.IsCM ? " cm" : " in"));
            }

            if (slider_type == "width") {
                that._range_slider.slider("option", "max", getSliderMaxValue(slider_type));
                slider_bar_1.html('0' + (that.IsCM ? " cm" : " in"));
                slider_bar_2.html(getSliderMaxValue(slider_type) + (that.IsCM ? " cm" : " in"));
            }

            if (slider_type == "price") {
                var badgesEle = $('[data-query-id=' + that._queryName + ']').closest(".filters-card-body").find('.badges-filter-block');
                var selected_currency = badgesEle.find('a.selected').text();
                that._range_slider.slider("option", "max", getSliderMaxValue(slider_type));
                var sign = badgesEle.find('a.selected').attr("data-sign");
                slider_bar_1.html(sign + ' 0');
                slider_bar_2.html(sign + " " + getSliderMaxValue(slider_type));
            }
        }
    }
}

// [module] badgesFilterModule
function badgesFilterModule(elem) {
    var that = this; // reference
    var protected = iModule.call(that, elem); // base

    //properties
    this.IsCM = null;

    // override methods
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.removeSelected = removeSelected;
    this.clearSelected = removeSelected;
    this.isPopulated = isPopulated;
    this.getSelectedTexts = getSelectedTexts;
    this.renderSelectedBedges = renderSelectedBedges;

    // helper function
    function getNumericRangeLabels() {
        var filterCardBody = that._elem.closest(".filters-card-body-container");
        var targetModules = that._elem.data('targetModules');
        if (targetModules && targetModules.length) {
            return $(targetModules.split(',').reduce(function (acc, module) {
                return acc.concat(filterCardBody.find(".numeric-range-module-block[data-query-name='" + module + "'] span.label-unit").toArray());
            }, []));
        } else {
            return filterCardBody.find(".numeric-range-module-block span.label-unit");
        }
    }

    // initialization
    (function (protected) {
        var filterCardBody = that._elem.closest(".filters-card-body-container");
        var numericRangeLables = getNumericRangeLabels();
        
        if (that._queryName == "currency") {
            var defaultVal = that._elem.attr('data-initial-value');
            var defaultEle = that._elem.find('a[data-id=' + defaultVal + ']');
            defaultEle.addClass('selected');
            numericRangeLables.text(defaultEle.text())
            that._elem.on("click", "a", function () {
                that._elem.find('a').removeClass('selected');
                $(this).addClass('selected');
                var sign = $(this).text();
                numericRangeLables.text(sign);
                filterCardBody.find(".default-currency-block").toggleClass('hidden', $(this).data("id") === that._elem.attr('data-initial-value'));
                //that.setSliderMaxRange();
                //that.setSlider();
            });
        } else {
            var defaultVal = that._elem.attr('data-initial-value');
            var defaultEle = that._elem.find('a[data-id=' + defaultVal + ']');
            var defaultSign = that._elem.find('a[data-id=' + defaultVal + ']').data('sign');

            if (defaultEle) {
                defaultEle.addClass('selected');
            }

            that.IsCM = defaultSign == "cm" ? true : false;
            that.IsCM = getParameterByName(that._queryName) == null ? that.IsCM : getParameterByName(that._queryName) == "1";

            numericRangeLables.text(that.IsCM ? "cm" : "in");

            var sizeEle = filterCardBody.find('.artwork-size-block');
            if (sizeEle.length > 0) {
                sizeEle.find('[data-sign]').addClass('hidden');
                sizeEle.find('[data-sign=' + (that.IsCM ? "cm" : "in") + ']').removeClass('hidden');
            }

            that._elem.on("click", "a", function () {
                var sign = $(this).text();
                if (!(that.IsCM && sign == "cm") && !(!that.IsCM && sign == "in")) {
                    that._elem.find('a').removeClass('selected');
                    $(this).addClass('selected');
                    filterCardBody.find(".default-currency-block").toggleClass('hidden', $(this).data("id") === that._elem.attr('data-initial-value'));
                    that.IsCM = sign == "cm" ? true : false;
                    numericRangeLables.text(that.IsCM ? "cm" : "in");
                    filterCardBody.find('.numeric-range-module-block input').each(function (index, element) {
                        if (element.value)
                            $(element).val(Math.round((that.IsCM ? element.value * 2.54 : element.value / 2.54)).toFixed(2));
                    });
                    //that.setSliderMaxRange();
                    //that.setSlider();
                    sizeEle.find('[data-sign]').addClass('hidden');
                    sizeEle.find('[data-sign=' + (that.IsCM ? "cm" : "in") + ']').removeClass('hidden');
                }
            });
        }

        var userPrefrenceInput = filterCardBody.find(".default-currency-block .save-as-default-preference");
        var userPrefInputContainer = userPrefrenceInput.closest(".checkbox-container");
        userPrefInputContainer.tooltip();
        userPrefrenceInput.on("click", function () {
            userPrefInputContainer.toggleClass("tooltip-hidden", !userPrefrenceInput.prop('checked'));
            if (!IsMobileView() && userPrefrenceInput.prop('checked'))
                userPrefInputContainer.trigger('mouseleave').trigger('mouseenter');
        });
    })(protected);

    function setSelected(val) {
        if (val === null || !val.length) return;
      
        var filterCardBody = that._elem.closest(".filters-card-body-container");
        var defaultVal = that._elem.attr('data-initial-value');
        //Dimention
        if (val[0] === '0' || val[0] === '1') {
            that.IsCM = val[0] === "1";
            that._elem.find('a').removeClass('selected');
            var targetElm = that._elem.find(`[data-sign=${that.IsCM ? "cm" : "in"}]`);
            $(targetElm).addClass('selected');

            var numericRangeLables = getNumericRangeLabels();
            numericRangeLables.text($(targetElm).text());

            var sizeEle = filterCardBody.find('.artwork-size-block');
            sizeEle.find('[data-sign]').addClass('hidden');
            sizeEle.find('[data-sign=' + (that.IsCM ? "cm" : "in") + ']').removeClass('hidden');

            filterCardBody.find(".default-currency-block").toggleClass('hidden', $(targetElm).data("id") === defaultVal);
        }
        //Currency
        else {
            that._elem.find('a').removeClass('selected');
            var targetElm = that._elem.find(`[data-id="${val[0]}"]`);
            $(targetElm).addClass('selected');

            var numericRangeLables = getNumericRangeLabels();
            numericRangeLables.text($(targetElm).text());

            filterCardBody.find(".default-currency-block").toggleClass('hidden', $(targetElm).data("id") === defaultVal);
        }
    }

    function getSelected() {
        if (that._queryName == "currency") {
            return [that._elem.find("a.selected").attr("data-id")];
        } else {
            return [that.IsCM ? 1 : 0];
        }
    }

    function removeSelected() {
        return;
    }

    function isPopulated() {
        let result = false;
        const numericElems = that._elem.closest(".filters-card-body-container").find('[data-module="numeric-range"]');
        numericElems.each(function (i, ele) {
            const query = $(ele).data('query-name');
            const queryModule = manager.getModulesByQueryString(query);
            if (queryModule && queryModule.length && queryModule[0].isPopulated && queryModule[0].isPopulated()) {
                result = true;
                return false; // Break the loop
            }
        });
        return result;
    }

    function getSelectedTexts() {
        return "";
    }

    function renderSelectedBedges() {
        return;
    }
}

// [module] sizeFilterModule
function sizeFilterModule(elem) {
    var that = this; // reference
    var protected = iModule.call(that, elem); // base

    //properties

    // override methods
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.getSelectedTexts = getSelectedTexts;

    // initialization
    (function (protected) {

        that._elem.closest('.artwork-size-block').find('i.m-icon-info').tooltip();

        that._elem.on("click", ".artwork-size-option", function () {
            that._elem.find('.artwork-size-option').removeClass('selected');
            $(this).addClass('selected');

            var values = `${$(this).data('val') }`.split('-');
            if (values && jQuery.isArray(values) && values.length > 1) {
                const selectedModule = manager.getModulesByQueryString('width');
                if (selectedModule.length && selectedModule[0].setSelected) {
                    selectedModule[0].setSelected([`${values[0]}-${values[1]}`]);
                }
            }
            // select parallel option
            var size = $(this).attr('data-size');
            if (size) {
                that._elem.find(`.artwork-size-options.hidden .artwork-size-option[data-size="${size}"]`).addClass('selected');
            }
        });
    })(protected);

    function setSelected(a, b) {
        return;
    }

    function getSelected() {
        return;
    }

    function isPopulated() {
        return true;
    }

    function getSelectedTexts() {
        return "";
    }
}

// [module] autoCompleteModule
function autoCompleteModule(elem) {
    var that = this; // reference

    var protected = iListModule.call(that, elem); // base

    // properties
    this._phraseInput = null;
    this.selectedValue = null;
    this.isDefault = true;
    this.focusResults = false;
    this._sendEmptyValue = false;
    this._sendEmptyValue = that._elem.data("send-empty") == "True";
    // override methods
    this.getItems = getItems;
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.bindItems = bindItems;
    this.getSelectedTexts = getSelectedText;

    // public methods
    this.getSearchPhrase = getSearchPhrase;
    this.clearSearchPhrase = clearSearchPhrase;
    this.removeSelected = removeSelected;
    this.renderSelectedBedges = renderSelectedBedges;
    this.clearSelected = removeSelected;

    // initialization
    (function (protected) {
        that._elem.addClass('autocomplete-module');
        that._phraseInput = that._elem.find('input[type="text"]:eq(0)');
        that._searchBtn = that._elem.find(".search-btn");

        var action = that._elem.attr('data-action');
        var d_def = that._elem.attr("data-default");
        that.isDefault = d_def != null && d_def.toLowerCase() == "true";

        var a_def = that._elem.attr("data-allowfreetext");
        that.allowFreeText = a_def != null && a_def.toLowerCase() == "true";

        var preVal = that.getSelected();
        if (that.isDefault && preVal && preVal.length)
            that._elem.find("input").val(preVal[0]);

        var provider = that._elem.attr('data-provider');
        if (provider) {
            protected.bindDataProviderUsingAutocomplete('keyup', that._phraseInput, provider, null, function (x) {
                if (action && !$(".mobile-filters-container").length) eval(action)(that, x);
            });
            if (that.focusResults == true) {
                protected.bindDataProviderUsingAutocomplete('focusin', that._phraseInput, provider, null, function (x) {
                    if (that._phraseInput.length === 0 && action) eval(action)(that, x);
                });
            }
        }

        that._elem.find(".close-autocomplete-input").on('click', function () {
            that._phraseInput.val('');
            that._phraseInput.keyup();
        });

        const onApplyFilter = () => {
            onFilterDoneClick();
        }

        if (action) {
            that._phraseInput.on('keyup', DoSearch);
            //that._phraseInput.focusout(DoSearch);
            if (that.allowFreeText)
                that._searchBtn.on('click', function () {
                    that.selectedValue = that.getSearchPhrase();
                    if ($(".mobile-filters-container").length) {
                        onApplyFilter();
                    }
                    eval(action)(that);
                });
        }
        function DoSearch(e) {
            if (that.allowFreeText) {
                if (that._phraseInput.val().length > 0)
                    that._searchBtn.addClass("active");
                else
                    that._searchBtn.removeClass("active");
            }

            if (e.keyCode == 13 || that._phraseInput.val().length < 1) {
                that.selectedValue = that.getSearchPhrase();
                if (!$(".mobile-filters-container").length)
                    eval(action)(that);
                else if (e.keyCode == 13) {
                    eval(action)(that);
                    onApplyFilter();
                }
            }
        }

        //ON SELECT OPTION
        that._list.on('click', 'li', function () {
            that._elem.removeClass("active");
            that._phraseInput.val(that._elem[0].classList.contains('search-for-query') ? $(this).data("value") : $(this).text());
            that._list.hide();
            that.selectedValue = $(this).data("value");
            that.selected = { value: $(this).data("value"), text: $(this).text() };
            if (action) eval(action)(that, { value: $(this).data("value"), text: $(this).text() });
            if ($(".mobile-filters-container").length) {
                onApplyFilter();
            }
            EmitEvent('FilterListClick', null, that._elem[0]);
        });

        protected.initCompleted(); // after fully loaded!
    })(protected);

    // methods
    function getItems() {
        // [ string ]
        var items = that._list.find('li');
        return items.toArray().map(function (x) { return $(x).text().trim(); });
    }

    function setSelected(data, textValue) {
        if (!data || !data.length) {
            that._phraseInput.val('');
            that._phraseInput.trigger('keyup');
            return;
        }

        if (textValue && that._saveFilteredTextInQuery) {
            var dataValue = data[0] || '';
            that.selectedValue = dataValue;
            that._phraseInput.val(textValue);
            that.selected = { value: dataValue, text: textValue };
        }
        else {
            that._phraseInput.val(data[0] || '');
            that.selectedValue = (data[0] || '');
        }

        that._phraseInput.trigger('keyup');
    }

    function removeSelected() {
        that.selected = null;
        that.selectedValue = '';
        that._phraseInput.val('');
    }

    function getSelected() {
        if (that.allowFreeText)
            return that.getSearchPhrase() ? [that.getSearchPhrase()] : null;
        if (that.selected && that.selected.value)
            return [that.selected.value];
        //if (getParameterByName(that._queryName))
        //    return [getParameterByName(that._queryName)];
        return null;
    }
    function getSelectedText() {
        if (that.allowFreeText)
            return that.getSearchPhrase() ? [that.getSearchPhrase()] : null;
        if (that.selected && that.selected.value)
            return [that.selected.text];
        //if (getParameterByName(that._queryName))
        //    return [getParameterByName(that._queryName)];
        return null;
    }

    function isPopulated() {
        return that.selected != null || getSelected() != null;
    }

    function bindItems(data) {
        // data [ string ]
        that.clearItems();
        if (!(data instanceof Array))
            return;
        that._elem.addClass("active");

        if (that._elem[0].classList.contains('search-for-query')) {
            let queryVal = that.getSearchPhrase();
            var html = "<li data-value='" + queryVal + "'><a class='main'>View all results for <em>\"" + queryVal + "\"</em></a></li>";
            that._list.append(html);
        }

        for (i in data)
            that._list.append('<li data-value="' + data[i].value + '">' + data[i].text + '</li>');
    }

    function getSearchPhrase() {
        var inptVal = that._phraseInput.val();
        if (that.focusResults == true && inptVal.length === 0)
            return "*";
        return inptVal.trim();
    }

    function clearSearchPhrase() {
        that._phraseInput.val('');
        that._phraseInput.trigger('keyup');
    }

    function renderSelectedBedges(parentEle) {
        var selectedFilterTexts = that.getSelected();
        $.each(selectedFilterTexts, function (key, value) {
            createBedge(value, that._queryName, that.getSearchPhrase(), parentEle);
        });
    }
}

// [module] checklistModule
function checklistModule(elem) {
    var that = this; // reference

    var protected = iListModule.call(that, elem); // base

    // override methods
    this.getItems = getItems;
    this.setSelected = setSelected;
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.bindItems = bindItems;
    this.getSelectedIds = getSelectedIds;
    this.countSelected = countSelected;
    this.getSelectedTexts = getSelectedTexts;
    this.getTextForFilter = getTextForFilter;
    this.getValueFormat = getValueFormat;
    this.removeSelected = removeSelected;
    this.renderSelectedBedges = renderSelectedBedges;

    // initialization
    (function (protected) {
        that._elem.addClass('checklist-module');

        var action = that._elem.attr('data-action');
        if (action) protected.bindAction('click', '> ul > li input', action, null, function (x) {
            // TODO [Temporary]
            var selectAllValue = '0A8E7073D5AD19A4';
            if (x.target.value == selectAllValue) {
                // select All
                var checkedStatus = x.target.checked;
                that.clearSelected();
                x.target.checked = checkedStatus;
            }
            else {
                // select Specific
                var item = that.findInput(selectAllValue).get(0);
                if (item) item.checked = false;
            }
        });

        protected.initCompleted(); // after fully loaded!
    })(protected);

    function bindItems(data) {
        // data [{ value, text, checked } ... ]

        that.clearItems();

        if (!(data instanceof Array))
            return;

        var template =
            '<li class="equalHMR eq">' +
            '<label class="checkbox-container checkbox-bordered checkbox-large" title="{3}">' +
            '<span class="text">{1}</span>' +
            '<input value="{0}" type="checkbox" {2} />' +
            '<span class="checkmark"></span>' +
            '</label>' +
            '</li>';

        for (i in data) {
            var item = data[i];
            that._list.append(template
                .replace('{0}', item.value)
                .replace('{1}', item.text)
                .replace('{2}', item.checked ? 'checked' : '')
                .replace('{3}', item.text)
            );
        }
    }

    // methods
    function getItems() {
        // [{ value, text, checked } ... ]
        var items = that._list.find('li');
        return items.toArray().map(function (x) {
            var input = $(x).find('input:checkbox');
            var label = $(x).find('label');
            return {
                value: input.val(),
                text: label.text().trim(),
                checked: input.attr('checked') ? true : false
            }
        });
    }

    function setSelected(data) {
        that.clearSelected();
        if (!(data instanceof Array)) {
            return;
        }

        // [ISSUE] doesn't work!!
        // that._list.find('input:checkbox[value="' + data[i] + '"]').attr('checked', 'checked')

        for (i in data) {
            var input = that._list.find('input:checkbox[value="' + data[i] + '"]')[0];
            if (input) input.checked = true
        }
    }

    function removeSelected(value) {
        var input = that._list.find('input:checkbox[value="' + value + '"]')[0];
        if (input) input.checked = false;
    }

    function getSelected() {
        return that.getSelectedIds();
    }

    function isPopulated() {
        return that.countSelected() > 0;
    }

    function bindItems(data) {
        // data [{ value, text, checked } ... ]

        that.clearItems();

        if (!(data instanceof Array))
            return;

        var template =
            '<li class="equalHMR eq">' +
            '<label class="checkbox-container checkbox-bordered checkbox-large" title="{3}">' +
            '<span class="text">{1}</span>' +
            '<input value="{0}" type="checkbox" {2} />' +
            '<span class="checkmark"></span>' +
            '</label>' +
            '</li>';

        for (i in data) {
            var item = data[i];
            that._list.append(template
                .replace('{0}', item.value)
                .replace('{1}', item.text)
                .replace('{2}', item.checked ? 'checked' : '')
                .replace('{3}', item.text)
            );
        }
    }

    function getSelectedIds() {
        var selected = that._list.find('input[type="checkbox"]:checked');
        return selected.toArray().map(function (x) { return x.value; });
    }

    function getSelectedTexts() {
        var selected = that._list.find('input[type="checkbox"]:checked');
        var txts = [];
        $(selected).each(function (item, index) {
            txts.push($(this).parent().children(".text").text().trim());
        });
        return txts;
    }

    function countSelected() {
        var selected = that._list.find('input[type="checkbox"]:checked');
        return selected.length;
    }

    function getTextForFilter() {
        if (that._elem.parents(".collapsable-title").length) {
            return protected.formatFilterText(that._elem.parents(".collapsable-title").find("span.filter-title span.title:first").text().trim(),
                that._elem.find('input[type="checkbox"]:checked').map(function () { return $(this).prev(".text").text(); }));
        }
        return null;
    }

    function getValueFormat() {
        return getSelectedTexts().join(', ');
    }

    function renderSelectedBedges(parentEle) {
        var selectedFilterTexts = that.getSelectedTexts();
        var selectedFilterIds = that.getSelectedIds();
        $.each(selectedFilterTexts, function (key, value) {
            createBedge(selectedFilterIds[key], that._queryName, value, parentEle);
        });
    }
}

// [module] radiolistModule
function radiolistModule(elem) {
    var that = this; // reference

    var protected = iListModule.call(that, elem); // base

    // override methods
    this.getItems = getItems;
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.bindItems = bindItems;
    this.getSelectedIds = getSelectedIds;
    this.countSelected = countSelected;
    this.getSelectedTexts = getSelectedTexts;

    // initialization
    (function (protected) {
        that._elem.addClass('radiolist-module');

        var action = that._elem.attr('data-action');
        if (action) protected.bindAction('click', '> ul > li input', action);

        protected.initCompleted(); // after fully loaded!
    })(protected);

    // methods
    function getItems() {
        // [{ value, text, checked } ... ]
        var items = that._list.find('li');
        return items.toArray().map(function (x) {
            var input = $(x).find('input:radio');
            var label = $(x).find('label');
            return {
                value: input.val(),
                text: label.text().trim(),
                checked: input.attr('checked') ? true : false
            }
        });
    }

    function setSelected(data) {
        if (!(data instanceof Array))
            return;

        that.clearSelected();

        for (i in data) {
            var input = that._list.find('input:radio[value="' + data[i] + '"]')[0];
            if (input) input.checked = true
        }
    }

    function getSelected() {
        return that.getSelectedIds();
    }

    function isPopulated() {
        return that.countSelected() > 0;
    }

    function bindItems(data) {
        // data [{ value, text, checked, group } ... ]

        that.clearItems();

        if (!(data instanceof Array))
            return;

        // TODO name
        var template =
            '<li>' +
            '<label class="radio-container" title="{4}">{1}' +
            '<input value="{0}" type="radio" name="{3}" {2} />' +
            '<span class="checkmark"></span>' +
            '</label>' +
            '</li>';

        for (i in data) {
            var item = data[i];
            that._list.append(template
                .replace('{0}', item.value)
                .replace('{1}', item.text)
                .replace('{2}', item.checked ? 'checked' : '')
                .replace('{3}', item.group || 'default')
                .replace('{4}', item.text)
            );
        }
    }

    function getSelectedIds() {
        var selected = that._list.find('input[type="radio"]:checked');
        return selected.toArray().map(function (x) { return x.value; });
    }

    function getSelectedTexts() {
        var selected = that._list.find('input[type="radio"]:checked');
        var txts = [];
        $(selected).each(function (item, index) {
            txts.push($(this).parent().text().trim());
        });
        return txts;
    }

    function countSelected() {
        var selected = that._list.find('input[type="radio"]:checked');
        return selected.length;
    }
}

// [module] radiolistAutoCompleteModule
function radiolistAutoCompleteModule(elem) {
    var that = this; // reference

    var protected = iListModule.call(that, elem); // base

    // properties
    this._phraseInput = null;
    this._remoteContent = false;

    // public methods
    this.getSearchPhrase = getSearchPhrase;
    this.searchItems = searchItems;

    // override methods
    this.getItems = getItems;
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.bindItems = bindItems;
    this.getSelectedIds = getSelectedIds;
    this.countSelected = countSelected;
    this.getSelectedTexts = getSelectedTexts;

    // initialization
    (function (protected) {
        that._elem.addClass('radiolist-autocomplete-module');

        that._phraseInput = that._elem.find('input[type="text"]:eq(0)');

        var provider = that._elem.attr('data-provider');
        if (provider) {
            that._remoteContent = true;
            protected.bindDataProviderUsingAutocomplete('keyup', that._phraseInput, provider);
        }
        else {
            that._remoteContent = false;
            that._elem.on('keyup', that._phraseInput, that.searchItems);
        }

        var action = that._elem.attr('data-action');
        if (action) protected.bindAction('click', '> ul > li input', action);

        protected.initCompleted(); // after fully loaded!
    })(protected);

    // methods
    function getItems() {
        // [{ value, text, checked } ... ]

        var items = that._list.find('li');
        return items.toArray().map(function (x) {
            var input = $(x).find('input:radio');
            var label = $(x).find('label');
            return {
                value: input.val(),
                text: label.text().trim(),
                checked: input.attr('checked') ? true : false
            }
        });
    }

    function setSelected(data) {
        if (!(data instanceof Array))
            return;

        that.clearSelected();

        for (i in data) {
            var input = that._list.find('input:radio[value="' + data[i] + '"]')[0];
            if (input) input.checked = true;
        }
    }

    function getSelected() {
        return that.getSelectedIds();
    }

    function isPopulated() {
        return that.countSelected() > 0;
    }

    function bindItems(data) {
        // data [{ value, text, checked, group } ... ]

        that.clearItems();

        if (!(data instanceof Array))
            return;

        // TODO name
        var template =
            '<li>' +
            '<label class="radio-container" title="{4}">{1}' +
            '<input value="{0}" type="radio" name="{3}" {2} />' +
            '<span class="checkmark"></span>' +
            '</label>' +
            '</li>';

        for (i in data) {
            var item = data[i];
            that._list.append(template
                .replace('{0}', item.value)
                .replace('{1}', item.text)
                .replace('{2}', item.checked ? 'checked' : '')
                .replace('{3}', item.group || 'default')
                .replace('{4}', item.text)
            );
        }
    }

    function searchItems() {
        var phrase = that.getSearchPhrase().trim();
        var phraseCount = phrase.length;

        // empty search value - clear items and don't trigger the event!
        if (that._EmptyIfNoPhrase && phraseCount == 0) {
            that.hideItems();
            return;
        }

        that.showItems();
        var values = that._list.find('li > label').toArray();
        var matches = values.filter(function (x) {
            return !($(x).text().trim().toLowerCase().includes(phrase.toLowerCase()));
        });
        matches.map(function (x) { $(x).closest('li').hide(); });
    }

    function getSelectedIds() {
        var selected = that._list.find('input[type="radio"]:checked');

        return selected.toArray().map(function (x) { return x.value; });
    }

    function getSelectedTexts() {
        var selected = that._list.find('input[type="radio"]:checked');
        var txts = [];
        $(selected).each(function (item, index) {
            txts.push($(this).parent().text().trim());
        });
        return txts;
    }

    function countSelected() {
        var selected = that._list.find('input[type="radio"]:checked');
        return selected.length;
    }

    function getSearchPhrase() {
        return that._phraseInput.val().trim();
    }
}

// [module] checklistAutoCompleteModule
function checklistAutoCompleteModule(elem) {
    var that = this; // reference

    var protected = iListModule.call(that, elem); // base

    // properties
    this._phraseInput = null;
    this._remoteContent = false;

    // public methods
    this.getSearchPhrase = getSearchPhrase;
    this.searchItems = searchItems;

    // override methods
    this.getItems = getItems;
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.bindItems = bindItems;
    this.getSelectedIds = getSelectedIds;
    this.countSelected = countSelected;
    this.getSelectedTexts = getSelectedTexts;
    this.removeSelected = removeSelected;
    this.renderSelectedBedges = renderSelectedBedges;
    // initialization
    (function (protected) {
        that._elem.addClass('checklist-autocomplete-module');

        that._phraseInput = that._elem.find('input[type="text"]:eq(0)');

        var provider = that._elem.attr('data-provider');
        if (provider) {
            that._remoteContent = true;
            protected.bindDataProviderUsingAutocomplete('keyup', that._phraseInput, provider);
        }
        else {
            that._remoteContent = false;
            that._elem.on('keyup', that._phraseInput, that.searchItems);
        }

        var action = that._elem.attr('data-action');
        if (action) protected.bindAction('click', '> ul > li input', action);

        protected.initCompleted(); // after fully loaded!
    })(protected);

    // methods
    function getItems() {
        // [{ value, text, checked } ... ]
        var items = that._list.find('li');
        return items.toArray().map(function (x) {
            var input = $(x).find('input:checkbox');
            var label = $(x).find('label');
            return {
                value: input.val(),
                text: label.text().trim(),
                checked: input.attr('checked') ? true : false
            }
        });
    }

    function setSelected(data) {
        that.clearSelected();
        if (!(data instanceof Array)) {
            return;
        }

        for (i in data) {
            var input = that._list.find('input:checkbox[value="' + data[i] + '"]')[0];
            if (input) input.checked = true
        }
    }

    function getSelected() {
        return that.getSelectedIds();
    }

    function removeSelected(value) {
        var input = that._list.find('input:checkbox[value="' + value + '"]')[0];
        if (input) input.checked = false;
    }

    function isPopulated() {
        return that.countSelected() > 0;
    }

    function bindItems(data) {
        // data [{ value, text, checked } ... ]

        that.clearItems();

        if (!(data instanceof Array))
            return;

        var template =
            '<li class="equalHMR eq">' +
            '<label class="checkbox-container checkbox-bordered checkbox-large">' +
            '<span class="text">{1}</span>' +
            '<input value="{0}" type="checkbox" {2} />' +
            '<span class="checkmark"></span>' +
            '</label>' +
            '</li>';

        for (i in data) {
            var item = data[i];
            that._list.append(template
                .replace('{0}', item.value)
                .replace('{1}', item.text)
                .replace('{2}', item.checked ? 'checked' : '')
            );
        }
    }

    function searchItems() {
        var phrase = that.getSearchPhrase().trim();
        var phraseCount = phrase.length;

        // empty search value - clear items and don't trigger the event!
        if (that._EmptyIfNoPhrase && phraseCount == 0) {
            that.hideItems();
            return;
        }

        that.showItems();
        var values = that._list.find('li > label').toArray();
        var matches = values.filter(function (x) {
            return !($(x).text().trim().toLowerCase().indexOf(phrase.toLowerCase()) > -1);
        });
        matches.map(function (x) { $(x).closest('li').hide(); });
    }

    function getSelectedIds() {
        var selected = that._list.find('input[type="checkbox"]:checked');
        return selected.toArray().map(function (x) { return x.value; });
    }

    function getSelectedTexts() {
        var selected = that._list.find('input[type="checkbox"]:checked');
        var txts = [];
        $(selected).each(function (item, index) {
            txts.push($(this).parent().text().trim());
        });
        return txts;
    }

    function countSelected() {
        var selected = that._list.find('input[type="checkbox"]:checked');
        return selected.length;
    }

    function getSearchPhrase() {
        return that._phraseInput.val().trim();
    }

    function renderSelectedBedges(parentEle) {
        var selectedFilterTexts = that.getSelectedTexts();
        var selectedFilterIds = that.getSelectedIds();
        $.each(selectedFilterTexts, function (key, value) {
            createBedge(selectedFilterIds[key], that._queryName, value, parentEle);
        });
    }
}

// [module] orientationFilterModule
function orientationFilterModule(elem) {
    var that = this; // reference    
    var protected = iModule.call(that, elem); // base
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.clearSelected = removeSelected;
    this.removeSelected = removeSelected;

    this.getSelectedTexts = getSelectedTexts;
    this.renderSelectedBedges = renderSelectedBedges;
    (function (protected) {
        that._elem.addClass('orientation-filter-module-block');        
        that._elem.find('.filter-orientation').on('click', function () {
            that._elem.find('.filter-orientation > div > div').removeClass('selected');
            $(this).find('div > div:eq(0)').addClass('selected');
        });

        protected.initCompleted();
    })(protected)

    function setSelected(data) {
        that.removeSelected();

        if (data != null) {
            that._elem.find(".filter-orientation > div > div[data-value='" + data + "']").addClass('selected');
        }
    }    
    function getSelected() {
        var selectedEle = that._elem.find(".filter-orientation > div > div.selected");
        if (selectedEle && selectedEle.length) 
            return [that._elem.find(".filter-orientation > div > div.selected").data("value")];        

        return '';
    }
    function isPopulated() {
        return that.getSelected() != '';
    }
    function removeSelected() {
            that._elem.find('.filter-orientation > div > div').removeClass('selected');
    }
    function getSelectedTexts() {
        return getSelected();
    }
    function renderSelectedBedges(parentEle) {
        var selectedFilterTexts = that.getSelected();
        $.each(selectedFilterTexts, function (key, value) {
            createBedge(value, that._queryName, value, parentEle);
        });
    }
}

function taglistAutoCompleteModule(elem) {
    var that = this; // reference

    var protected = iListModule.call(that, elem); // base

    // properties
    this._phraseInput = null;
    this._selectedList = null;

    // public methods
    this.getSearchPhrase = getSearchPhrase;
    this.clearSearchPhrase = clearSearchPhrase;
    this.addToList = addToList;
    this.removeFromList = removeFromList;

    // override methods
    this.getItems = getItems;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.bindItems = bindItems;
    this.getSelectedIds = getSelectedIds;
    this.countSelected = countSelected;
    this.searchByValue = searchByValue;
    this.getSelectedTexts = getSelectedTexts;

    // initialization
    (function (protected) {
        //that._elem.addClass('checklist-addToList-module');
        that.newDesign = that._elem.data("new-checkmark")
        // 2nd ul (_autoCompleteList) is not exists - add it
        var autoCompleteDiv = that._elem.find('div.inputcont');
        var ulExists = autoCompleteDiv.find('ul').length > 0;

        that._autoCompleteList = ulExists ? autoCompleteDiv.find('ul:first') : $('<ul />');

        autoCompleteDiv.append(that._autoCompleteList);

        that.OnCreateTag = that._elem.data("create-action");

        that._list = that._elem.find("div.taglist");

        that.showOnFocus = that._elem.data("show-before-type");

        that.initScrollbar(that._autoCompleteList);

        that._phraseInput = that._elem.find('input[type="text"]:eq(0)');

        var provider = that._elem.attr('data-provider');
        if (provider) {
            //TODO: on enter
            that._phraseInput.on('keydown', function (e) {
                if (e.keyCode == 13 && that._autoCompleteList.find("li").length) {
                    var frst = that._autoCompleteList.find("li").first();
                    if (frst) {
                        selectItem(frst.find('input').val(), frst.text())
                        e.stopPropagation();
                    }
                }
            });

            protected.bindDataProviderUsingAutocomplete('keyup', that._phraseInput, provider, that._autoCompleteList);
            if (that.focusResults == true) {
                protected.bindDataProviderUsingAutocomplete('focusin', that._phraseInput, provider, that._autoCompleteList, function (x) {
                    //if (that._phraseInput.length === 0 && action) eval(action)(that, x);
                });
            }
        }

        var action = that._elem.attr('data-action');
        self.action = action;
        protected.bindAction('click', '.taglist a[data-close]', function (m, x) {
            that.removeFromList(x);

            if (action) eval(action)(that, this);
        });

        that._autoCompleteList.on('click', 'li', function () {
            var _val = $(this).find('input').val();
            var _text = $(this).text();
            selectItem(_val, _text);
        });

        protected.initCompleted(); // after fully loaded!
    })(protected);

    function selectItem(_val, _text) {
        if (_text.startsWith("Create ") && _val == "create") {
            _text = _text.substring(8, _text.length - 1);
            mixpanel.track(that.CreateEventName, { "Name": _text });
            if (that.OnCreateTag) {
                var d = eval(that.OnCreateTag)(_text, that);
            }
        } else {
            that.addToList({ text: _text, value: _val });
        }
        //EmitEvent('SelectItem', {
        //    IsNew: _text.startsWith("Create ") && _val == "create",
        //    Text: _text
        //}, self._elem[0]);
        that._autoCompleteList.hide();

        // user action
        if (self.action) eval(self.action)(that, this);
        that.clearSearchPhrase()
    }

    // methods
    function getItems() {
        // [{ value, text, checked } ... ]
        var items = that._list.find('li');
        return items.toArray().map(function (x) {
            var input = $(x).find('input:checkbox');
            var label = $(x).find('label');
            return {
                value: input.val(),
                text: label.text().trim(),
                checked: input.attr('checked') ? true : false
            }
        });
    }

    function getSelected() {
        return that.getSelectedIds();
    }

    function isPopulated() {
        return that.countSelected() > 0;
    }

    function addToList(item) {
        var existsItem = that.searchByValue(item.value);
        if (existsItem) return;

        var template = '<span data-id="{0}">{1} <a data-close>&times;</a></span>';

        that._list.append(template
            .replace('{0}', item.value)
            .replace('{1}', item.text)
        );
    }

    function removeFromList(item) {
        $(item).closest('span').remove();
    }

    function getSearchPhrase() {
        var inptVal = that._phraseInput.val();
        //if (that.focusResults == true && inptVal.length === 0)
        //    return "*";
        return inptVal.trim();
    }

    function clearSearchPhrase() {
        that._phraseInput.val('');
        that._phraseInput.trigger('keyup');
    }

    function bindItems(data) {
        // data [ { text, value } ... ]
        that.clearItems(that._autoCompleteList);
        if (!(data instanceof Array))
            return;
        var phrs = that.getSearchPhrase();

        for (i in data) {
            var item = data[i];
            that._autoCompleteList.append('<li>' + makeBold(item.text, phrs) + '<input type="hidden" value="' + item.value + '" /></li>');
        }

        if (that.allowCreate && that.getSearchPhrase().length > 2 && !data.length) {
            that._autoCompleteList.append('<li>Create "' + (that.CapitalizeCreate ? titleCase(that.getSearchPhrase()) : that.getSearchPhrase()) + '"<input type="hidden" value="create" /></li>');
        }
    }

    function getSelectedIds() {
        var selected = that._list.find('span');
        return selected.toArray().map(function (x) { return x.dataset.id; });
    }

    function getSelectedTexts() {
        var selected = that._list.find('span');
        var txts = [];
        $(selected).each(function (item, index) {
            txts.push($(this).contents(0)[0].textContent.trim());
        });
        return txts;
    }

    function countSelected() {
        var selected = that._list.find('span');
        return selected.length;
    }

    function searchByValue(value) {
        var selector = that._list.find('span[data-id="' + value + '"]');
        return selector.length == 0 ? null : selector.first();
    }
}

// [module] checklistAddToListModule
function checklistAddToListModule(elem) {
    var that = this; // reference

    var protected = iListModule.call(that, elem); // base

    // properties
    this._phraseInput = null;
    this._selectedList = null;
    this._AdditionalQueryName = null;

    // public methods
    this.getSearchPhrase = getSearchPhrase;
    this.clearSearchPhrase = clearSearchPhrase;
    this.addToList = addToList;
    this.removeFromList = removeFromList;

    // override methods
    this.getItems = getItems;
    this.setSelected = setSelected;
    this.getSelected = getSelected;
    this.isPopulated = isPopulated;
    this.bindItems = bindItems;
    this.getSelectedIds = getSelectedIds;
    this.countSelected = countSelected;
    this.searchByValue = searchByValue;
    this.getSelectedTexts = getSelectedTexts;
    this.removeSelected = removeSelected;
    this.renderSelectedBedges = renderSelectedBedges;
    this.getAdditionalSelected = getAdditionalSelected;
    this.removeAdditionalSelected = removeAdditionalSelected;

    // initialization
    (function (protected) {
        that._elem.addClass('checklist-addToList-module');
        that.newDesign = that._elem.data("new-checkmark")

        that.searchAll = that._elem.data("search-all");
        that._AdditionalQueryName = that._elem.data("additional-query-name");

        // 2nd ul (_autoCompleteList) is not exists - add it
        var autoCompleteDiv = that._elem.find('div');
        var ulExists = autoCompleteDiv.find('ul').length > 0;
        that._autoCompleteList = ulExists ? autoCompleteDiv.find('ul:first') : $('<ul />');
        autoCompleteDiv.append(that._autoCompleteList);

        that.initScrollbar(that._autoCompleteList);

        that._phraseInput = that._elem.find('input[type="text"]:eq(0)');

        var provider = that._elem.attr('data-provider');
        if (provider) protected.bindDataProviderUsingAutocomplete('keyup', that._phraseInput, provider, that._autoCompleteList);

        var action = that._elem.attr('data-action');

        protected.bindAction('click', '> ul > li input, > ul > li label.ma-checkbox-label, ul > li > span[data-close]', function (m, x) {
            that.removeFromList(x);
            // user action
            if (action) eval(action)(that, this);
        });

        that._autoCompleteList.on('click', 'li', function () {
            var _val = $(this).find('input').val();
            var _text = $(this).text();
            if (_text.startsWith("Create ") && _val == "create") {
                _text = _text.substring(8, _text.length - 1);
                mixpanel.track(that.CreateEventName, { "Name": _text });
            }
            
            if (_text.startsWith("Search for ") && _val == "searchAll") {
                that.getSelected().includes('searchAll')
                _text = _text.substring(12, _text.length - 1);                
            }

            that.addToList({ text: _text, value: _val });
            that._autoCompleteList.hide();

            // user action
            if (action) eval(action)(that, this);
            that.clearSearchPhrase()
        });

        protected.initCompleted(); // after fully loaded!
    })(protected);

    // methods
    function getItems() {
        // [{ value, text, checked } ... ]
        var items = that._list.find('li');
        return items.toArray().map(function (x) {
            var input = $(x).find('input:checkbox');
            var label = $(x).find('label');
            return {
                value: input.val(),
                text: label.text().trim(),
                checked: input.attr('checked') ? true : false
            }
        });
    }

    function setSelected(data) {
        that.clearSelected();
        if (!(data instanceof Array)) {
            return;
        }

        for (i in data) {
            var input = that._list.find('input:checkbox[value="' + data[i] + '"]')[0];
            if (input) input.checked = true
        }
    }

    function removeSelected(value) {
        var input = that._list.find('input:checkbox[value="' + value + '"]')[0];
        if (input) input.checked = false;
    }

    function getSelected() {
        return that.getSelectedIds();
    }

    function isPopulated() {
        return that.countSelected() > 0;
    }

    function addToList(item) {
        // { text, value }
        if (that.countSelected() > 2)
            return;
        var existsItem = that.searchByValue(item.value);
        if (existsItem) {
            if (item.value != 'searchAll') return;

            var existsSearchAll = that._list.find('li input[value="searchAll"]');
            if (existsSearchAll) {
                existsSearchAll.closest('li').remove();
            }
        }

        var template =
            '<li class="equalHMR eq">' +
            '<label class="checkbox-container checkbox-bordered checkbox-large">' +
            '<span class="text position-initial">{1}</span>' +
            '<input value="{0}" type="checkbox" checked />' +
            '<span class="checkmark"></span>' +
            '</label>' +
            '</li>';
        if (that.newDesign) {
            //template = '<li><input class="ma-checkbox" type="checkbox" value="{0}" checked />' +
            //    '<label class="ma-checkbox-label" title="Artist Name">{1}</label></li>';

            template = '<li data-value="{0}">{1} <span data-close><i class="m-icon-clear"></i></span>';
            //template = '<li><label class="theme-checkbox path">' +
            //    '<input type="checkbox" value="{0}" checked />' +
            //    '<svg viewBox="0 0 21 21"><path d="M5,10.75 L8.5,14.25 L19.4,2.3 C18.8333333,1.43333333 18.0333333,1 17,1 L4,1 C2.35,1 1,2.35 1,4 L1,17 C1,18.65 2.35,20 4,20 L17,20 C18.65,20 20,18.65 20,17 L20,7.99769186"></path></svg>' +
            //    '</label>' +
            //    '<span>{1}</span>' +
            //    '</li>';
        }

        that._list.append(template
            .replace('{0}', item.value)
            .replace('{1}', item.text)
        );
    }

    function removeFromList(item) {
        // item: checkbox
        if (item.checked) return;
        $(item).closest('li').remove();
        if (that.countSelected() < 1) {
            protected.protected.setClearActive(false)
        }
    }

    function getSearchPhrase() {
        return that._phraseInput.val().trim();
    }

    function clearSearchPhrase() {
        that._phraseInput.val('');
        that._phraseInput.trigger('keyup');
    }

    function bindItems(data) {
        // data [ { text, value } ... ]

        that.clearItems(that._autoCompleteList);

        if (!(data instanceof Array))
            return;

        var phrs = that.getSearchPhrase();

        if (that.allowCreate && that.getSearchPhrase() != "*" && !data.length) {
            that._autoCompleteList.append('<li>Create "' + (that.CapitalizeCreate ? titleCase(that.getSearchPhrase()) : that.getSearchPhrase()) + '"<input type="hidden" value="create" /></li>');
        }

        if (that.searchAll == 'True' && that.getSearchPhrase() != "*") {
            that._autoCompleteList.append('<li>Search for "' + (that.CapitalizeCreate ? titleCase(that.getSearchPhrase()) : that.getSearchPhrase()) + '"<input type="hidden" value="searchAll" /></li>');
        }

        for (i in data) {
            var item = data[i];
            that._autoCompleteList.append('<li>' + makeBold(item.text, phrs) + '<input type="hidden" value="' + item.value + '" /></li>');
        }
    }

    function getSelectedIds() {
        if (that.newDesign) {
            return that._list.find("li").map(function (i, x) { return x.dataset.value; });
        }
        var selected = that._list.find('input[type="checkbox"]:checked');
        return selected.toArray().filter(x => x.value != 'searchAll').map(function (x) { return x.value; });
    }

    function getSelectedTexts() {
        if (that.newDesign)
            return that._list.find("li").map(function (i, x) { return x.innerText.trim(); });
        var selected = that._list.find('input[type="checkbox"]:checked');
        var txts = [];
        $(selected).each(function (item, index) {
            //if (that.newDesign)
            //    txts.push(selected.next().text().trim());
            //else
            var text = $(this).parent().text().trim();
            if ($(this).val().trim() !== "searchAll") {  // Exclude "searchAll"
                txts.push(text);
            }

        });
        return txts;
    }

    function countSelected() {
        var selected = that._list.find('input[type="checkbox"]:checked');
        return selected.length;
    }

    function searchByValue(value) {
        var selector = that._list.find('input[type="checkbox"][value="' + value + '"]');
        return selector.length == 0 ? null : selector.first();
    }

    function renderSelectedBedges(parentEle) {
        var selectedFilterTexts = that.getSelectedTexts();
        var selectedFilterIds = that.getSelectedIds();
        var selectedAdditinalFilterTxt = that.getAdditionalSelected();
        $.each(selectedFilterTexts, function (key, value) {

            createBedge(selectedFilterIds[key], that._queryName, value, parentEle);
        });

        if (selectedAdditinalFilterTxt != '' || selectedAdditinalFilterTxt != null) {
            createBedge('searchAll', that._queryName, selectedAdditinalFilterTxt, parentEle);
        }

    }

    function getAdditionalSelected() {
        var selectedText = that._list
            .find('input[type="checkbox"]:checked')
            .filter(function () {
                return $(this).val() === "searchAll";
            })
            .closest("li")
            .find("span.text")
            .text();

        return selectedText;


    }

    function removeAdditionalSelected(val) {
        if (val == 'searchAll') {
            var input = that._list.find('input:checkbox[value="searchAll"]')[0];
            if (input) input.checked = false;
        }
    }
}

/******* Manager *******
************************/

// TODO should i move that into the manager ?!

// query expansion
jQuery.fn.extend({
    loadMAModules: function () {
        var arr = [];
        $(this).find('[data-module]').each(function (i, x) {
            var moduleType = $(x).attr('data-module').toLowerCase();
            switch (moduleType) {
                case 'numeric-range': arr.push(new numericRangeModule(x));
                    break;
                case 'badges-filter': arr.push(new badgesFilterModule(x));
                    break;
                case 'size-filter': arr.push(new sizeFilterModule(x));
                    break;
                case 'date-range': arr.push(new dateRangeModule(x));
                    break;
                case 'autocomplete': arr.push(new autoCompleteModule(x));
                    break;
                case 'checklist': arr.push(new checklistModule(x));
                    break;
                case 'radiolist-autocomplete': arr.push(new radiolistAutoCompleteModule(x));
                    break;
                case 'checklist-autocomplete': arr.push(new checklistAutoCompleteModule(x));
                    break;
                case 'taglist-autocomplete': arr.push(new taglistAutoCompleteModule(x));
                    break;
                case 'dropdown-module': arr.push(new dropdownModule(x));
                    break;
                case 'radiolist': arr.push(new radiolistModule(x));
                    break;
                case 'checklist-addtolist': arr.push(new checklistAddToListModule(x));
                    break;
                case 'freesearch': arr.push(new freeSearchModule(x));
                    break;
                case 'period-switcher': arr.push(new periodSwitcherModule(x));
                    break;
                case 'tags': arr.push(new tagsModule(x));
                    break;
                case 'orientation-filter': arr.push(new orientationFilterModule(x));
                    break;
            }
        });

        return arr;
    },
    loadSingleMAModule: function (id) {
        var modElem = $(this).find("#" + id);
        var modName = $(modElem).attr("data-module");
        if (modName) {
            switch (modName.toLowerCase()) {
                case 'numeric-range': return new numericRangeModule(modElem);
                    break;
                case 'badges-filter': return new badgesFilterModule(modElem);
                    break;
                case 'size-filter': return new sizeFilterModule(modElem);
                    break;
                case 'autocomplete': return new autoCompleteModule(modElem);
                    break;
                case 'checklist': return new checklistModule(modElem);
                    break;
                case 'date-range': return new dateRangeModule(modElem);
                    break;
                case 'radiolist-autocomplete': return new radiolistAutoCompleteModule(modElem);
                    break;
                case 'checklist-autocomplete': return new checklistAutoCompleteModule(modElem);
                    break;
                case 'taglist-autocomplete': return new taglistAutoCompleteModule(modElem);
                    break;
                case 'dropdown-module': return new dropdownModule(modElem);
                    break;
                case 'radiolist': return new radiolistModule(modElem);
                    break;
                case 'checklist-addtolist': return new checklistAddToListModule(modElem);
                    break;
                case 'freesearch': return new freeSearchModule(modElem);
                    break;
                case 'period-switcher': return new periodSwitcherModule(modElem);
                    break;
                case 'tags': return new tagsModule(modElem);
                    break;
                case 'orientation-filter': arr.push(new orientationFilterModule(modElem));
                    break;
            }
        }
        return null;
    },
    findMAModule: function (arrModules) {
        // get by DOM reference

        for (i in arrModules)
            if (arrModules[i].equal(this[0]))
                return arrModules[i];
        return null;
    },
    collapseAll: function (arrModules) {
        $(this).each(function (i, x) {
            var elem = $(x).first();

            var arr = [];

            elem.find('[data-module]').each(function (i, x) {
                var module = $(x).findMAModule(arrModules);
                if (!module) return;
                arr.push(module);
            });

            // console.log(arr.length);
            var isAnyonePopulated = false;
            for (i in arr)
                if (arr[i] instanceof iModule)
                    if (arr[i].isPopulated()) {
                        isAnyonePopulated = true;
                        break;
                    }

            // console.log(totalSelected);

            if (isAnyonePopulated)
                elem.removeClass('collapsed');
            else
                elem.addClass('collapsed');

            // for (i in arr) arr[i].hide();
        });
    }
});

// --------------------------------

// helper
var modulesManagerHelper = function () {
    return {
        // query 2 dictionary
        // { key, value }
        parseParams: function (customUrl) {
            var result = [];

            var query = document.location.search.replace('?', '');
            if (customUrl && customUrl.indexOf('?') > -1) {
                query = customUrl.substring(customUrl.indexOf('?'), customUrl.length);
            }
            if (query.trim() == 0)
                return result;

            query = query.replace(/\+/g, '%20');
            query = decodeURIComponent(query);

            var arr = query.split('&');
            for (i in arr) {
                var param = arr[i].split('=');
                result[param[0]] = param[1];
            }

            return result;
        },

        // dictionary 2 query
        // { key, value }
        createQuery: function (dic) {
            var res = this.dic2arr(dic).reduce(function (s, x) {
                return s.concat('&', x.key, '=', x.value && typeof (x.value) == "object" ? x.value.join('_') : x.value);
            }, '');

            // replace first & to ? mark
            if (res.indexOf('&') == 0)
                res = '?'.concat(res.slice(1));

            return res;
        },
        dic2arr: function (dic) {
            var arr = [];

            for (i in dic)
                arr.push({ key: i, value: dic[i] });

            return arr;
        }
    }
}

// --------------------------------
// modules manager
var modulesManagerService = function () {
    var that = this; // reference

    var lastResultHeight = 0;

    this._modules = [];
    this._helper = null;
    this.shadowTextQuerySuffix = 'Text';
    that._miniFilterContainer = $(".mini-filter-display");
    that._miniFilterData = $("#mini-filter-data");
    that._filters = $(".showhide-filters");
    that._dashList = $(".dashboard_list");
    that._footer = $("#footer");
    var disableButton = false;
    var isSendMixpanel = true;
    // initialization
    (function () {
        that._helper = new modulesManagerHelper();
        if (that._miniFilterContainer.length && !IsPage('my_preferences') && ((!$("body").hasClass("mobile-always-filter")) || IsPage('artist_graphs'))) {
            window.addEventListener('scroll', onFilterPageScroll, { passive: true });
            window.addEventListener('resize', onFilterPageScroll, { passive: true });
            $(".collapsable-title").click(reFlowFilterHeight);

            window.addEventListener('moduleQueryChange', _onModuleQueryChangeEvent);
        }
        $("#jumpToTop").on("click", (e) => {
            mixpanel.track('Click on arrow', { 'CTA Name': 'arrow button' });
            onJumpToTopClick(e)
        });
        $('.open-filters-fixed').on('click', onFilterFixedClick);
        $('.collapsable-title').on("click", function (e) {
            let lazyFilter = $(this).find('.filter-title span.title[data-is-lazy-filter=true]');

            if (lazyFilter && lazyFilter.length) {
                let filterLoaders = lazyFilter.parents('.collapsable-title') ? lazyFilter.parents('.collapsable-title').find('.filters-card .filters-card-body span.filter-ajax-loader') :  null;
                if (filterLoaders && filterLoaders.length) {
                    let promises = [];

                    filterLoaders.each(function (index, filterLoader) {
                        let promise = manager.lazyLoadModuleContent($(filterLoader).attr('id'));
                        promises.push(promise);
                    });

                    Promise.all(promises).then((results) => {
                        // All modules are fetched and added to the DOM, now initialize them
                        results.forEach(result => {
                            if (result && result.filterId) {
                                manager.loadSingleModule(result.filterId);
                            }
                        });

                        manager.setFilterBedges();
                        EmitEvent('managerLoaded');
                    }).catch((error) => {
                        var mixpannelProp = {
                            'Error': error
                        };
                        mixpanel.track('Lazy load filter error', mixpannelProp);
                    });
                }
            }
        });
    })();

    that.LoadChartTags = function () {
        for (var index in that._modules) {
            if (that._modules[index] instanceof tagsModule) {
                that._modules[index].bindData();
            }
        }
    }

    function _onModuleQueryChangeEvent(e) {
        if (e.detail.hasQsChanged) {
            that._filters = $(".showhide-filters").removeAttr("style").removeClass("absolute active");
            that._dashList.css("padding-bottom", 0);
            disableButton = false;
        }
        //lastResultHeight = that._dashList.height();
    }

    function onJumpToTopClick(e) {
        $('html,body').animate({ scrollTop: 0 }, 400);
    }

    function toggleArtworksCompareBar(isShow) {
        if (entitySelection.getStoredValue().items.length > 0) {
            if (isShow) {
                $('.artist-auction-bottom-bar').show();
            }else {
                $('.artist-auction-bottom-bar').hide();
            }
        }
    }

    function reFlowFilterHeight(e) {
        var setheight = that._filters[0].clientHeight;
        if (IsPage('artist_artworks-for-sale')) {
            var ele_textonfilter = $('.for-sale')[0];
            setheight += ele_textonfilter ? ele_textonfilter.clientHeight : 0;
        }
        else if (IsPage('artist_auctionresults')) {
            var ele_textonfilter = $('.at-auction')[0];
            setheight += ele_textonfilter ? ele_textonfilter.clientHeight : 0;
        }
        that._dashList.css("min-height", setheight);
    }

    function onFilterFixedClick() {
        clickedToggle = true;
        var $flt = $(".filter-container-filters");
        //$("html, body").animate({ scrollTop: 250 }, "slow");
        //that._filters.addClass("sticky-filters active").scroll();
        //onFilterPageScroll(true);
        //StickyHandler();
        that._dashList.css("padding-bottom", that._filters.height() + "px");
        if (!IsPage('my_collection/artwork') && !disableButton && that._footer.length && that._footer.offset().top - $(window).scrollTop() < 1000) {
            //$("html, body").animate({
            //    scrollTop: $(window).scrollTop() - 1500
            //}, 200);

            disableButton = true;
        }
        if (disableButton) {
            //$([document.documentElement, document.body]).animate({
            //    scrollTop: window.scrollY - 10 - (1500 - (that._footer.length && that._footer.offset().top - $(window).scrollTop()))
            //}, 200);
            //that._dashList.css("padding-bottom", "100px");
            disableButton = false;
        }

        $("html, body").animate({
            scrollTop: $(window).scrollTop() - 1000
        }, 0);
        isSendMixpanel = false;
        $('.collapsable-title:first .filter-title').click();

        isSendMixpanel = true;

    }

    var lastScrollTop = 0;
    var clickedToggle = false;    
    //var lastScrollDown = false;

    function onFilterPageScroll(isFromClick) {
        if (!isFromClick && that._footer.length && that._footer.offset().top - $(window).scrollTop() < 1000) {
            return false;
        }
        if (window.innerWidth <= 1024) {
            that._filters.removeAttr("style");
            return;
        }
        if (window.scrollY > 600) {
            $("#jumpToTop").fadeIn(200);
        } else {
            $("#jumpToTop").fadeOut(200);
        }
        reFlowFilterHeight();

        //if (document.body.offsetHeight <= 1200 || window.scrollY < 300) {
        //    that._filters.removeClass("absolute");
        //    that._filters.removeClass("sticky-filters active").removeAttr("style");
        //} else {
        //    that._filters.addClass("absolute");
        //}

        if (window['_resultsCount'] && parseInt(window['_resultsCount']) < 2 || $(".dashboard_list .ring-loader").length)
            return;

        var st = $(this).scrollTop();
        //var isScrollDown = st > lastScrollTop;

        var htElm = $(".filter-container-filters").height();
        var offset = that._filters.offset().top - 90;
        const filterMobileTextHeight = ($(".filters-mobile-text").length > 0 ? $(".filters-mobile-text").height() : 0);
        const alternativeLocationsHeight = ($(".alternative-locations").length > 0 ? $(".alternative-locations").height() + 40 : 0);

        if (window.scrollY > 3960 && IsPage('artist_graphs')) {
            that._miniFilterContainer.removeClass("fixed");
            return;
        }

        //if (clickedToggle) {
        //    if (isScrollDown && !lastScrollDown && isFromClick !== true) { //SCROLL DOWN
        //        var filterRect = that._filters[0].getBoundingClientRect();
        //        var listerContainer = $(".auction-table-items-section").length ? $(".auction-table-items-section") : $(".ExhibitionSearchResults .content-two-cols");
        //        var auctionDataDistanceFromTop = listerContainer.offset().top;
        //        var newTop = that._filters.offset().top - auctionDataDistanceFromTop - filterRect.top;
        //        if (newTop < that._filters.offset().top) {
        //            that._filters.css("top", newTop + 80);
        //        }
        //        that._filters.removeClass("active");
        //    } else if (!isScrollDown || isFromClick === true) { //SCROLL UP
        //        if ($(window).scrollTop() < 260) { //Top Of Page
        //            that._filters.removeClass("sticky-filters active").removeAttr("style");
        //        }
        //        else if (that._filters.offset().top - $(window).scrollTop() > 112) {
        //            that._filters.css("top", "").addClass("active")
        //            //StickyHandler();
        //        }
        //    }
        //}
        //lastScrollDown = isScrollDown;
        //var offset = 0;
        if (window.scrollY <= htElm + offset + 80 + ($(".filter-bubble-section").length > 0 ? $(".filter-bubble-section").height() : 0) + filterMobileTextHeight + alternativeLocationsHeight) {
            that._miniFilterContainer.removeClass("fixed");
        } else if (window.scrollY >= (htElm + offset + 80 + filterMobileTextHeight + alternativeLocationsHeight)) {
            that._miniFilterContainer.addClass("fixed");
        }
        lastScrollTop = st;
    }

    function getMiniFilterHTML() {
        var longText = "";
        for (i in that._modules) {
            var current = that._modules[i];
            var hasSearchAll = current.searchAll && current.getAdditionalSelected && current.getAdditionalSelected() !== ""; // checklistAddToListModule module

            if (!hasSearchAll && (!current._queryName || !current.isPopulated() || current.getSelected() == "")) continue;

            if (hasSearchAll) {
                var additionalSelected = current.getAdditionalSelected();
            }

            var selected = current.getSelectedTexts();
            //if (current._queryName == "lotsLocation")
            //    selected = current.selected.text;
            if ((selected && selected.length) || (additionalSelected && additionalSelected.length)) {
                var additionalLen = additionalSelected ? 1 : 0;
                var additionalText = additionalSelected ? additionalSelected : "";
                var selectedJoinText = current.getValueFormat ? current.getValueFormat() : selected.join(', ');
                var header = current._elem.parents(".collapsable-title").find("span.filter-title span.title:first");
                var fltCount = current._typeName == "iRangeModule" ? 1 : (selected.length + additionalLen);
                
                var selectedText = selectedJoinText && additionalText ? selectedJoinText + ", " + additionalText : selectedJoinText || additionalText;

                if (header && header.length)
                    longText += "<div role='button' onclick='manager.openSpecificFilter(event)' data-tag-type='{3}'><strong>{0} ({1})</strong> {2}</div>".format(header.text(), fltCount, selectedText, current._queryName);
            }
        }
        return longText;
    }

    function loadFilterMini() {
        if (that._miniFilterData.length) {
            that._miniFilterData.html(getMiniFilterHTML());
        }
    }

    function closeFilterBox() {
        UncheckDefaultPreferences();
        closeFilterBoxSize();
        manager.loadQuery();
        manager.ToggleFilterControls(false);
        $('.filters-card').find('.action-done').css('pointer-events', 'auto');
    }

    function sendFilterTabMixpanelEvent(filterTab) {
        const selectedFilterTab = $(filterTab).find('span.title:first').text().trim();
        let appliedFiltersTabName = manager.getAppliedFilterTabNames();
        var mixpannelProp = {
            'Filter Type': selectedFilterTab,
            'Is Reusing?': appliedFiltersTabName.map(x => x.toLowerCase()).includes(selectedFilterTab.toLowerCase()),
            'Page Name': page_name,
        };
        if (mixpannelProp['Is Reusing?']) {
            mixpannelProp['Filtered'] = appliedFiltersTabName.join(', ').replace(/,([^,]*)$/, ' and$1');
        }
        if (trackFilterTabClicks.previousFilterTabs.length) {
            const prevTabsText = trackFilterTabClicks.previousFilterTabs.join(', ').replace(/,([^,]*)$/, ' and$1');
            mixpannelProp['Previous Filter Types'] = prevTabsText;
        }
        mixpannelProp['CTA Name'] = "Tab Button";
        mixpanel.track('Filter Tab click', mixpannelProp);
        trackFilterTabClicks.previousFilterTabs.unshift(selectedFilterTab);
    }

    return {
        getModulesByClass: function (qs) {
            return that._modules ? that._modules.filter(function (f) { return f._elem.hasClass(qs); }) : null;
        },
        getModulesByQueryString: function (qs) {
            return qs && that._modules ? that._modules.filter(function (f) { return (f._queryName == qs || f._AdditionalQueryName == qs); }) : null;
        },
        modules: function () {
            return that._modules
        },
        count: function () {
            return that._modules.length;
        },
        loadQuery: function (customUri) {            
            var dicPrms = that._helper.parseParams(customUri);
            for (i in that._modules) {
                var textParamValue = null;
                var current = that._modules[i];
                if (!current._queryName) continue;

                var additionalRaw = dicPrms[current._AdditionalQueryName];
                if (additionalRaw) {
                    current.addToList({ text: additionalRaw, value: "searchAll"});
                    continue;
                }

                // get raw query value (before splitting it)
                var raw = dicPrms[current._queryName];
                if (!raw) {
                    current.setSelected(null);
                    continue;
                }

                if (current._saveFilteredTextInQuery) {
                    textParamValue = dicPrms[current._queryName + that.shadowTextQuerySuffix]
                }

                // get values collection
                var values = raw.split('_');
                current.setSelected(values, textParamValue);
                current.setClearActive(current.isPopulated());
            }
            loadFilterMini();
            SetActiveFilterFlag();
        },
        
        lazyLoadModulesFromQuery: function (customUri) {
            let lazyModules = [];
            let dicPrms = that._helper.parseParams(customUri);

            if (dicPrms && Object.keys(dicPrms).length) {
                $('.filters-card-body-container').each(function (index, filterBodyContainer) {
                    let filterLoaders = $(filterBodyContainer).find('.filter-ajax-loader[data-lazy-query-name]');
                    if (filterLoaders && filterLoaders.length) {
                        let existsInDicPrms = false;

                        filterLoaders.each(function () {
                            let lazyQueryName = $(this).data('lazy-query-name');

                            if (lazyQueryName && dicPrms[lazyQueryName]) {
                                existsInDicPrms = true;
                                return false; // Break the loop
                            }
                        });

                        if (existsInDicPrms) {
                            filterLoaders.each(function (index, filterLoader) {
                                let lazyModule = manager.lazyLoadModuleContent($(filterLoader).attr('id'));
                                lazyModules.push(lazyModule);
                            });
                        }

                    }
                })

                Promise.all(lazyModules).then((results) => {
                    // All modules are fetched and added to the DOM, now initialize them
                    results.forEach(result => {
                        if (result && result.filterId) {
                            manager.loadSingleModule(result.filterId);
                        }
                    });

                    manager.loadQuery();
                    manager.setFilterBedges();
                    EmitEvent('managerLoaded');
                }).catch((error) => {
                    var mixpannelProp = {
                        'Error': error
                    };
                    mixpanel.track('Lazy load filter error', mixpannelProp);
                });
            }
        },
        lazyLoadModuleContent: function (eleId, noSpinner) {
            if (eleId) {
                let filterLoader = $('#' + eleId);
                if (filterLoader && filterLoader.length) {
                    return loadFilterContent(filterLoader, noSpinner)
                        .then((data) => {
                            return manager.addLazyModuleToModuleManager(data);
                        })
                        .catch((error) => {
                            let filterLoader = $('#' + error.filterId);
                            var mixpannelProp = {
                                'Error': error.rText,
                                'Lazy Query Name': filterLoader.data('lazyQueryName')
                            };
                            mixpanel.track('Lazy load filter error', mixpannelProp);
                        })
                }
            }
            return Promise.resolve();
        },
        addLazyModuleToModuleManager: function (promiseResponse, callback) {
            if (promiseResponse && promiseResponse.status === 'success') {
                let filterLoader = $('#' + promiseResponse.filterId);

                if (filterLoader && filterLoader.length) {
                    let filterBody = filterLoader.parent('.filters-card-body-container');

                    var tempContainer = $('<div>').append($(promiseResponse.rText));
                    tempContainer.find('[data-module]').attr('id', promiseResponse.filterId);
                    filterLoader.replaceWith(tempContainer.children());

                    tempContainer.remove();

                    if (filterBody && filterBody.length) {
                        let filterModule = filterBody.find("#" + promiseResponse.filterId);
                        if (filterModule && filterModule.length) {
                            return promiseResponse;
                        }
                    }
                }
            }
            return Promise.reject(new Error("Failed to load module"));
        },
        queryCount: function () {
            var dicPrms = that._helper.parseParams();
            var _counter = 0;
            for (i in that._modules) {
                var current = that._modules[i];
                var hasSearchAll = current.searchAll && current.getAdditionalSelected && current.getAdditionalSelected() !== ""; // checklistAddToListModule module
                if (!hasSearchAll && 
                    (!current._queryName || current._ignoreCount || !current.isPopulated() || current.getSelected() == "")) continue;

                var raw = dicPrms[current._queryName] || dicPrms[current._AdditionalQueryName];
                if (!raw) continue;

                if (current._elem && current._queryName != "artworkSort" && current._queryName != 'groupBy' && current._elem.data('ignore-count') !== "True")
                    _counter++;
            }
            return _counter;
        },
        upcomingFilterQueryCount: function () {
            var dicPrms = that._helper.parseParams();
            var reqFilters = ["price", "lotsNationality", "saleTitle", "artworkTitle", "tags", "mediumText", "year", "height", "width", "prices"];
            var _counter = 0;
            for (i in that._modules) {
                var current = that._modules[i];
                if (!current._queryName || current._ignoreCount || !current.isPopulated() || current.getSelected() == "") continue;

                var raw = dicPrms[current._queryName];
                if (!raw) continue;

                if (current._elem && reqFilters.includes(current._queryName))
                    _counter++;
            }
            return _counter;
        },
        removeQuery: function (qName, qValue) {
            let dicPrms = that._helper.parseParams();
            for (i in that._modules) {
                var current = that._modules[i];
                if (current._queryName == qName) {
                    // get raw query value (before splitting it)
                    var raw = dicPrms[current._queryName];
                    if (!raw) continue;
                    // get values collection
                    var values = raw.split('_');

                    for (var i in values) {
                        if (values[i] == qValue)
                            values.splice(i, 1);
                    }

                    current.setSelected(values);
                }
            }
        },
        clearQuery: function () {
            for (i in that._modules) {
                var current = that._modules[i];
                if (current["clearSelected"]) {
                    current.clearSelected();
                }
                //current.setSelected(null);
            }
            onFilterDoneClick();
        },
        getFilterText: function () {
            var longText = "";
            for (i in that._modules) {
                var current = that._modules[i];
                if (!current._queryName || !current.isPopulated() || current.getSelected() == "") continue;

                // skip sort filter
                if (current._elem.data('ignore') == "True") continue;

                if (current.getTextForFilter != null && current.getTextForFilter() != null) {
                    if (i > 0 && longText != "")
                        longText += ", ";
                    longText += current.getTextForFilter();
                }
            }
            return longText;
        },
        getSavedFilterText: function () {
            if (IsPage("auction_search") && window.location.pathname == "/auction-search") {
                //return "Auction Lot Search " +
            }
        },
        ToggleFilterControls: function (state, isFromFooter) {
            if ($(".mobile-filters-container").length) {
                if (!IsMobileView() && !$("body").hasClass("mobile-always-filter")) {
                    $("body").removeClass("filters-active");
                    $('.modal-backdrop-ma').fadeOut(200, null, function () {
                        $(this).remove();
                        $("body").off(_touchEvent, onOutsideLotFilterClick);
                    });
                    toggleArtworksCompareBar(!state);
                    return;
                }
                var _touchEvent = ('ontouchstart') in window ? 'touchstart' : 'click';
                if (state == true || (typeof (state) == undefined && !$("body").hasClass("filters-active"))) {
                    $("body").addClass("filters-active");
                    $('<div class="modal-backdrop-ma"></div>').hide().appendTo(document.body).fadeIn(200, function () {
                        $("body").on(_touchEvent, onOutsideLotFilterClick);
                    });
                    GTM_Send("event", "lot search", 'Open Filters', 'Mobile Filters');
                    mixpanel.track("Open Filters", { 'CTA Name': `Mobile ${isFromFooter ? 'footer':'header'} button`});
                } else {
                    $("body").removeClass("filters-active");
                    $('.modal-backdrop-ma').fadeOut(200, null, function () {
                        $(this).remove();
                        $("body").off(_touchEvent, onOutsideLotFilterClick);
                    });
                    GTM_Send("event", "lot search", 'Close Filters', 'Mobile Filters');
                    mixpanel.track("Close Filters");
                    this.getOnlyQuery() != window.location.search && onJumpToTopClick();
                }
            }
        },
        getQuery: function (extraQuery) {
            return ''.concat(document.location.protocol, '//', window.location.host, window.location.pathname, this.getOnlyQuery(extraQuery));
        },
        getOnlyQuery: function (extraQuery) {
            var dicPrms = {};
            that.LoadChartTags();

            for (i in that._modules) {
                var current = that._modules[i];

                var hasSearchAll = current.searchAll && current.getAdditionalSelected && current.getAdditionalSelected() !== ""; // checklistAddToListModule module
                if (!hasSearchAll
                    && (!current._queryName
                        || (current.getSelected() == null && !hasSearchAll)
                        || (!current._sendEmptyValue && (!current.isPopulated() || current.getSelected() == "")))
                )
                    continue;

                dicPrms[current._queryName] = current.getSelected();

                if (current._AdditionalQueryName != null && current.getAdditionalSelected != undefined) {
                    dicPrms[current._AdditionalQueryName] = current.getAdditionalSelected();
                }
            }

            var query = that._helper.createQuery(dicPrms);

            if (extraQuery)
                query = query.concat('&', extraQuery);

            if (query.indexOf('?') == -1 && query.indexOf('&') > -1)
                query = query.replace('&', '?');

            //console.log(query);

            return query;
        },
        setQuery: function (extraQuery) {
            that._filters.css("min-height", (window.scrollY + window.innerHeight) + 'px');
            that._filters.css("min-height", 'auto');
            var dicPrms = {};
            that.LoadChartTags();
            var _counter = 0;
            var moduleQueries = that._modules.map(function (m) {
                return m._elem.data("query-name")
            }).filter(function (f) {
                return !!f;
            });
            var knownQueries = [];

            for (i in that._modules) {
                var shadowTextQuery = null;
                var current = that._modules[i];
                if (!current._queryName)
                    continue;
                knownQueries.push(current._queryName);

                //WHY? Because when original queryParam is not valid in that case, we need to also remove its shadow queryParam from the URL and Filter.
                if (current._saveFilteredTextInQuery) {
                    shadowTextQuery = current._queryName + that.shadowTextQuerySuffix;
                    if (!dicPrms[shadowTextQuery]) {
                        knownQueries.push(shadowTextQuery);
                    }
                }


                if (!dicPrms[current._AdditionalQueryName]) {
                    knownQueries.push(current._AdditionalQueryName);
                }

                var hasSearchAll = current.searchAll && current.getAdditionalSelected && current.getAdditionalSelected() !== ""; // checklistAddToListModule module
                if (!hasSearchAll && (current.getSelected() == null || (!current._sendEmptyValue && (!current.isPopulated() || current.getSelected() == "")))) {
                    if (shadowTextQuery && knownQueries[shadowTextQuery]) {
                        knownQueries.splice($.inArray(shadowTextQuery, knownQueries), 1);
                    }
                    continue;
                }

                var queryParam = current.getSelected();
                if (queryParam != '' && queryParam != null) {                    
                    queryParam = typeof (queryParam) == "object"
                        ? queryParam.map(x => encodeURIComponent(x))
                        : encodeURIComponent(queryParam);

                    dicPrms[current._queryName] = queryParam;
                }

                if (shadowTextQuery && !dicPrms[shadowTextQuery]) {
                    dicPrms[shadowTextQuery] = current.getSelectedTexts();
                }


                if (current._AdditionalQueryName != null && current.getAdditionalSelected != undefined) {
                    var additionalParam = current.getAdditionalSelected()
                    if (additionalParam) {
                        dicPrms[current._AdditionalQueryName] = additionalParam;
                    }
                }

                if (current._elem && current._elem.data("query-name") != "artworkSort" && current._elem.data('ignore-count') !== true)
                    _counter++;
            }

            var query = that._helper.createQuery(dicPrms);

            if (extraQuery && (window["page_name"] == null || !IsPage('artist_artworks')))
                query = query.concat('&', extraQuery);

            if (query.indexOf('?') == -1 && query.indexOf('&') > -1)
                query = query.replace('&', '?');

            var newURI = ''.concat(document.location.protocol, '//', window.location.host, window.location.pathname, query)

            if (IsPage('analyticshub_artistperformance')) {
                if (window.location.hash != null || window.location.hash != "") {
                    newURI = newURI + window.location.hash;
                }
            }

            var hasQsChanged = query != window.location.search; // Not equal to previous query

            EmitEvent('moduleQueryChange', {
                hasQsChanged: hasQsChanged,
                hasQs: query != "",
                Qs: query,
                queryCount: _counter
            });

            if (hasQsChanged) {
                if (!ScopedVariables['DisableFilterJump']) {
                    //$([document.documentElement, document.body]).animate({
                    //    scrollTop: $(".page-content").offset().top + 60
                    //}, 500);

                    //if ($(".filter-section").length > 0) {
                    //    $([document.documentElement, document.body]).animate({
                    //        scrollTop: $(".filter-section").offset().top - 200
                    //    }, 500);
                    //}
                }
                if (window.location.search) {
                    var searchP = new URLSearchParams(window.location.search);
                    var uriP = new URLSearchParams(query);
                    searchP.forEach(function (v, k) {
                        if (knownQueries.indexOf(k) === -1) {
                            uriP.append(k, v);
                        }
                    })
                    newURI = ''.concat(document.location.protocol, '//', window.location.host, window.location.pathname)
                    if (uriP.toString() !== '') newURI += '?' + uriP.toString();
                }
                window.history.pushState({ urlPath: newURI }, "", newURI);
            }

            loadFilterMini();
            SetActiveFilterFlag();
            if (!getCookie('.ASPXFORMSAUTH') && (dicPrms && Object.keys(dicPrms).length)) {
                setCookie("RedirectUrl", window.location.pathname + window.location.search);
            }
        },
        loadModules: function () {
            // modules
            that._modules = $(document).loadMAModules();
        },
        loadSingleModule: function (id) {
            var module = $(document).loadSingleMAModule(id);
            if (module) {
                that._modules.push(module);
            }
            return module;
        },
        loadCollapsableTitles: function () {
            // collapsable titles
            var selector = $('.collapsable-title');

            // onload - ignore those with data-ignore-collapse attribute
            //selector.not('[data-ignore-collapse]').collapseAll(that._modules);
            selector.addClass("collapsed");

            var header = selector.find('span:first');
            header.click(function (e) { 
                if(isSendMixpanel) sendFilterTabMixpanelEvent(this);

                var isCollapsed = $(this).parent().hasClass('collapsed');
                if ($('.filter-section').length > 0) {
                    if (isCollapsed) {
                        selector.addClass("collapsed");
                        $(this).parent().removeClass('collapsed');
                        manager.checkPageHeightForFilterBox();
                        //manager.loadQuery();
                        //manager.setFilterBedges();
                        //EmitEvent('managerLoaded');
                        SetCardSize();
                        setTimeout(SetCardSize, 500);
                        if (!IsMobileView() && !$("body").hasClass("mobile-always-filter"))
                            toggleArtworksCompareBar(false);
                    }
                    return;
                } else {
                    selector.addClass("collapsed");
                    if (isCollapsed) {
                        $(this).parent().removeClass('collapsed');
                    } else {
                        $(this).parent().addClass('collapsed');
                        manager.checkPageHeightForFilterBox();
                    }
                }
            });
        },
        loadALL: function () {
            this.addFilterBubbleSection();
            this.loadModules();
            this.loadQuery();
            this.lazyLoadModulesFromQuery();
            //this.addLazyModuleToModuleManager();
            this.lazyLoadModuleContent();
            this.loadCollapsableTitles();
            this.registerEvents();
            this.setFilterBedges();
            this.trackAdditionalFilterEvents();
            this.setFilterFromPopularTitles();
        },
        registerEvents: function () {
            return;
            // any click on the page should clear the autocomplete values state
            $('body').click(function (x) {
                for (i in that._modules) {
                    let current = that._modules[i];
                    if (current instanceof autoCompleteModule || current instanceof checklistAddToListModule) {
                        current.clearSearchPhrase();
                        x.stopPropagation();
                    }
                }
            });
        },
        hasQuery: function () {
            var qs = window.location.href.split("?")[1];
            if (qs) {
                for (i in that._modules) {
                    var current = that._modules[i];
                    if ((current._queryName && qs.indexOf(current._queryName + '=') !== -1) || (current._AdditionalQueryName && qs.indexOf(current._AdditionalQueryName + '=') !== -1)) return true;
                }
            }
            return false;
        },
        checkPageHeightForFilterBox: function () {
            setTimeout(function () {
                if ($('.filter-section').length > 0 & !IsMobileView()) {
                    var p_h = $('.page-content').height();
                    var f_h = $('.filters-card').height();
                    var d_h = $('.bubble-placed-to').offset().top - $('.page-content').offset().top;
                    if ((f_h + d_h) > p_h) {
                        $('footer#footer').css('marginTop', (f_h + d_h + 20) - p_h);
                    } else {
                        $('footer#footer').css('marginTop', 0);
                    }
                } else {
                    $('footer#footer').css('marginTop', 0);
                }
            }, 5)
        },
        getSearchQueryList: function () {
            var keys = [];
            for (i in that._modules) {
                var current = that._modules[i];

                var hasSearchAll = current.searchAll && current.getAdditionalSelected && current.getAdditionalSelected() !== ""; // checklistAddToListModule module

                if (!hasSearchAll && (!current._queryName || !current.isPopulated() || current.getSelected() == "")) continue;

                // skip sort filter
                if (current._elem.data('ignore') == "True") continue;

                if (current.getSelectedTexts != null && current.getSelectedTexts() != null) {
                    keys.push(current.getSelectedTexts());
                }

                if (hasSearchAll) {
                    keys.push(current.getAdditionalSelected());
                }
            }
            return keys;
        },
        getAppliedFilterTabNames: function () {
            var keys = [];
            for (i in that._modules) {
                var current = that._modules[i];
                if (!current._queryName || !current.isPopulated() || current.getSelected() == "") continue;

                // skip sort filter
                if (current._elem.data('ignore') == "True") continue;

                if (current.getSelectedTexts != null && current.getSelectedTexts() != null) {
                    keys.push(current._elem.parents(".collapsable-title").find("span.filter-title span.title").text().trim().split('\n')[0]);
                }
            }
            return keys;
        },
        sendApplyFilterButtonMixpanelEvent: function (mixpannelProp) {
            mixpannelProp["Full Url"] = manager.getQuery();
            var queryList = manager.getSearchQueryList();
            var selectedTabs = manager.getAppliedFilterTabNames();
            for (i in queryList) {
                if (mixpannelProp[selectedTabs[i]]) {
                    mixpannelProp[selectedTabs[i]] = mixpannelProp[selectedTabs[i]] + ' ' + queryList[i];
                }
                else {
                    mixpannelProp[selectedTabs[i]] = Array.isArray(queryList[i]) ? queryList[i] : queryList[i].replace(selectedTabs[i] + ': ', '');
                }
            }           
            mixpannelProp["Filter Types"] = selectedTabs.filter(function (item, index) { return selectedTabs.indexOf(item) == index });
            if (!mixpannelProp["Artists"]) {
                if (IsPage('artist_artworks') || IsPage('artist_auctionresults') || IsPage('artist_exhibitions') || IsPage('artist_artworks-for-sale'))
                    mixpannelProp["Artists"] = document.getElementById('artist-name') ? document.getElementById('artist-name').textContent : null;
            }

            var searchType = "";
            if (IsPage('artist_discovery')) {
                searchType = 'Artist Discovery';
            } else if ((IsPage('auction_search') && document.location.href.indexOf('auction-search') > -1)
                || IsPage('artist_auctionresults') || IsPage('artist_artworks-for-sale') || IsPage('auction_auctionresults')) {
                searchType = 'Auction';
            } else if (IsPage('artwork_similar') || IsPage('artist_artworks') || IsPage('artworks_for_sale') || (IsPage('auction_search') && document.location.href.indexOf('buy-art') > -1)) {
                searchType = 'Artwork';
            } else if (IsPage('artist_exhibitions')) {
                searchType = 'Artist Exhibitions';
            }
            if (searchType != "")
                mixpannelProp["Search Type"] = searchType;
            mixpanel.track('Apply Filter Button', mixpannelProp);

        },
        setFilterFromPopularTitles: function myfunction() {
            $('.filters-card-body').on('click', '.badge-popular-title', function (e) {
                var ele = $(this);
                var q_name = ele.parents('.dashboard-filter-panel').data('moduleParam');
                var selectedModule = manager.getModulesByQueryString(q_name);
                if (selectedModule && selectedModule.length > 0) {
                    var curModule = selectedModule[0];
                    var paramValue = $(e.target).data('paramValue').split('_');
                    if (curModule && paramValue) {
                        curModule.setSelected(paramValue);
                        if ($(".mobile-filters-container").length) {
                            onFilterDoneClick();
                            var title = ele.parents('.filters-card-body').find('.card-body-title:first').text();
                            var mixpannelProp = {
                                'Filter Tab': title,
                                'Filter Selection Type': 'Popular'
                            };
                            manager.sendApplyFilterButtonMixpanelEvent(mixpannelProp);
                        }
                    }
                }
            });
        },
        trackAdditionalFilterEvents: function myfunction() {
            $('.filters-card-body [data-module=autocomplete]').on('click', 'ul.module-scrollbar li', function (e) {
                var ele = $(this);
                var title = ele.parents('.filters-card-body').find('.card-body-title:first').text();
                var mixpannelProp = {
                    'Filter Tab': title,
                    'CTA Name': ele.text(),
                    'Filter Selection Type': 'Suggestions'
                };
                manager.sendApplyFilterButtonMixpanelEvent(mixpannelProp);
            });

            $(".action-done").on('click', function (e) {
                var ele = $(e.target);
                if (ele.hasClass('dont-track-callback')) {
                    ele.removeClass('dont-track-callback');
                    return;
                }

                let filterBody = $(ele).parents('.filters-card').find('.filters-card-body');
                if (filterBody) {
                    const filterTabName = filterBody.find('span.card-body-title') ? filterBody.find('span.card-body-title').text() : null;
                    let mixpannelProp = { 'Filter Tab': filterTabName };

                    let checkEle = filterBody.find('.filters-card-body-container input.save-as-default-preference');

                    if (checkEle && checkEle.is(":checked")) {
                        let preferenceEle = filterBody.find('.badges-filter-block[data-preference-type]');

                        if (preferenceEle) {
                            let preferenceProp = {
                                'CTA Name': ele.text(),
                                'Save as Default': true,
                                'Preference Type': preferenceEle.data('preferenceType'),
                                'Preference Value': $(preferenceEle).find('a.badge-pill.selected').text()
                            }
                            mixpannelProp = { ...mixpannelProp, ...preferenceProp };
                        }
                    }
                    if (IsPage('exhibitionsearchresults') && filterTabName == 'Artists') {
                        const isShowFollowed = location.search ? location.search.getValueByKey("showFollowed") == '1' : false;
                        const selected = $('#ex_artist_list').find('input[type="checkbox"]:checked');
                        if (selected.length > 0) {
                            const artistsNameArray = selected.map((i, elem) => {
                                return $(elem).parent().text().trim();
                            }).get();

                            const lastArtist = artistsNameArray.pop();
                            let artistsNameCSV = artistsNameArray.join(', ');
                            artistsNameCSV += artistsNameArray.length > 0
                                ? isShowFollowed
                                    ? `, ${lastArtist} and Following Artists`
                                    : ` and ${lastArtist}`
                                : lastArtist + (isShowFollowed ? ' and Following Artists' : '');

                            mixpannelProp["Section"] = `Artist${(artistsNameArray.length > 0 ? "s" : "")} ${artistsNameCSV}`;
                        }
                        else if (isShowFollowed) {
                            mixpannelProp["Section"] = "Following Artist";
                        }
                    }
                    if (filterTabName == 'Size') {
                        const selectedSize = filterBody.find('.artwork-size-block .artwork-size-option.selected');
                        mixpannelProp["Shape"] = selectedSize && selectedSize.length > 0;
                    }
                    manager.sendApplyFilterButtonMixpanelEvent(mixpannelProp);

                }
            });
        },
        addFilterBubbleSection: function () {
            $(".action-done").on('click', function (e) {
                UpdateUserDefaultPreference(e);
                if (IsPage('auction_search') && location.pathname.toLowerCase() == '/auction-search' && allowed == '0' && !isAbUser()) {
                    closeFilterBox();
                    return;
                }
                onFilterDoneClick(e);
            });

            if (!IsPage('my_collection/albums') && !IsPage('my_collection/album')) {
                $('.filter-section').prepend(`<div class="filter-bubble-section"></div>`);
            }

            $('.filter-section').on('click', '.btn-select-bubble', function (e) {
                var ele = $(this);
                var q_name = ele.parent().data('tag-type');
                var selectedModule = manager.getModulesByQueryString(q_name);
                if (selectedModule && selectedModule.length > 0) {
                    if (selectedModule[0]._elem.hasClass('filter-sort')) {
                        selectedModule[0]._elem.find('ul').addClass('active');
                    } else {
                        const collapsableTitle = selectedModule[0]._elem.closest('.collapsable-title');
                        const filterTab = collapsableTitle.find('span:first');
                        closeFilterBoxSize();
                        collapsableTitle.removeClass('collapsed');
                        SetCardSize();
                        manager.checkPageHeightForFilterBox();
                        manager.ToggleFilterControls(true);

                        sendFilterTabMixpanelEvent(filterTab);
                    }
                }
            });

            $('.filter-section').on('click', '.btn-remove-bubble', function (e) {
                var ele = $(this);
                var val = ele.parent().data('val');
                var q_name = ele.parent().data('tag-type');
                var selectedModule = manager.getModulesByQueryString(q_name);
                if (selectedModule && selectedModule.length > 0) {
                    manager.loadQuery();
                    selectedModule[0].removeSelected(val);

                    var hasSearchAll = selectedModule[0].searchAll && selectedModule[0].getAdditionalSelected && selectedModule[0].getAdditionalSelected() !== ""; // checklistAddToListModule module
                    if (hasSearchAll) {
                        selectedModule[0].removeAdditionalSelected(val);
                    }

                    ele.parent().remove();
                    onFilterDoneClick();
                    $("body").removeClass("filters-active");
                    $('.modal-backdrop-ma').fadeOut(200, null, function () {
                        $(this).remove();
                        var _touchEvent = ('ontouchstart') in window ? 'touchstart' : 'click';
                        $("body").off(_touchEvent, onOutsideLotFilterClick);
                    });
                }
            });

            $('.filter-section').on('click', '.btn-clear-filters', function (e) {
                if (IsPage('auction_search') && location.pathname.toLowerCase() == '/auction-search' && allowed == '0' && !isAbUser()) {
                    closeFilterBox();
                    return;
                }

                closeFilterBox();
                $(this).parent().parent().find('[data-query-name]').each(function (index, item) {
                    var q_name = $(item).data("query-name");
                    var selectedModule = manager.getModulesByQueryString(q_name);
                    if (selectedModule && selectedModule.length > 0) {
                        if ($(item).hasClass('ajax-check-list')) {
                            selectedModule[0].clearSelected($(item).children());
                        }
                        else {
                            selectedModule[0].clearSelected();
                        }
                    }
                });

                //closeFilterBoxSize();
                onFilterDoneClick();
                $("body").removeClass("filters-active");
                $('.modal-backdrop-ma').fadeOut(200, null, function () {
                    $(this).remove();
                    var _touchEvent = ('ontouchstart') in window ? 'touchstart' : 'click';
                    $("body").off(_touchEvent, onOutsideLotFilterClick);
                });

                var title = $(this).parent().parent().find('.card-body-title').text();
                mixpanel.track('Clear Filter Button', { 'Filter Tab': title });
                $('.filters-card').find('.action-done').css('pointer-events', 'auto');
            });

            $('.filter-section').on('click', '.back-to-list', function (e) {
                UncheckDefaultPreferences();
                closeFilterBoxSize();
                manager.loadQuery();
                $('.filters-card').find('.action-done').css('pointer-events', 'auto');
            });

            $('.filter-section').on('click', '.close-filter', function (e) {
                closeFilterBox();
            });

            $(window).resize(function () {
                SetCardSize();
                manager.setFilterBedges();
            });
        },
        setFilterBedges: function () {
            SetCardSize();
            if (IsPage('analyticshub_artmarketanalysis') && !$('#mobile-hub-tab-nav').hasClass('mobile-hub-nav')) {
                $('#mobile-hub-tab-nav').addClass('mobile-hub-nav');
            }
            var analyticspages = ['analyticshub_artistperformance', 'analyticshub_performanceatauction', 'analyticshub_similarlotcomparison'];
            if (analyticspages.includes(page_name)) {
                $('#mobile-hub-tab-nav').hide();
                $('.hub-tab-nav').hide();
                $('#desktop_nav_toggle').hide();
                if (IsMobileView()) {
                    if (IsPage('analyticshub_artistperformance')) {
                        $('#mobile-hub-tab-nav').css('display', 'block');
                    }
                } else {
                    $('.hub-tab-nav').css('display', 'block');
                    $('#desktop_nav_toggle').css('display', 'block');
                }
                if (!IsPage('analyticshub_similarlotcomparison')) {
                    return;
                }
            }
            //if (IsPage('exhibitionsearchresults_browsemap')) {
            //    $('.filters-header-mobile').css('display', IsMobileView() ? 'none': 'block')
            //}
            var ele_bubble_placed_to = $('.bubble-placed-to');
            var ele_filter_section = $('.filter-section');

            if (ele_bubble_placed_to.length > 0 && ele_filter_section.length > 0) {
                var prop_marginTop = 'marginTop';
                var prop_display = 'display';

                var page_artwork_similar = 'artwork_similar';
                var artworks_for_sale_page = 'artworks_for_sale';

                var ele_filter_container_tags = $('#filters-container-tags > .tags-list');
                var ele_filter_bubble_section = $(".filter-bubble-section");
                var ele_dashboard_list = $('.dashboard_list');
                var ele_filters_card = ele_filter_section.find('.filters-card');
                var ele_collection_management_table = $('#collection-management-table');
                var ele_collection_grid = $('#collection-grid');
                var ele_management_table_container = $('.management-table-container');
                var ele_mobile_always_filter = $('.mobile-always-filter');
                var ele_artist_filter_save = $('.artist-filter-save');
                var ele_compared_lot = $('.compared-lot');

                ele_filter_container_tags.html("");
                ele_filter_bubble_section.html("");
                ele_filter_bubble_section.css(prop_marginTop, 0);
                ele_dashboard_list.css(prop_marginTop, 0);
                ele_bubble_placed_to.css(prop_marginTop, 0);
                ele_filters_card.css(prop_marginTop, 0);
                ele_collection_management_table.css(prop_marginTop, 0);
                ele_collection_grid.css(prop_marginTop, 0);
                ele_management_table_container.css(prop_marginTop, 0);
                $('.results-wrapper').css(prop_marginTop, 0);

                if (ele_artist_filter_save.length) {
                    $(".artist-filter-save").css("display", manager.hasQuery() ? "block" : "none");
                    var upcomingLotFilter = IsPage('auction_search') && manager.hasQuery() && manager.upcomingFilterQueryCount() < 2;
                    $(".artist-filter-save .filter_save_step_1 a").css("background-color", upcomingLotFilter ? "gray" : "#131721");
                    $(".artist-filter-save .filter_save_step_1 a").attr("data-tooltip", upcomingLotFilter ? "Add more criteria to activate the filter" : "");
                    $(".artist-filter-save .filter_save_step_1 a").attr("onclick", upcomingLotFilter ? "" : "ArtistModule.open_step_three()");
                    if (upcomingLotFilter)
                        $(".artist-filter-save .filter_save_step_1 a").addClass("v2__tooltip--left");
                    else
                        $(".artist-filter-save .filter_save_step_1 a").removeClass("v2__tooltip--left");
                }
                const hasQuery = manager.hasQuery()
                if (hasQuery) {
                    populateFilterBedges();
                    if (ele_filter_bubble_section.height() > 0) {
                        if (ele_collection_management_table.length > 0 || ele_collection_grid.length > 0 || ele_management_table_container.length > 0) {
                            var ele = ele_collection_management_table;
                            ele = ele.length > 0 && ele.css(prop_display) != 'none' ? ele : ele_collection_grid;
                            ele = ele.length > 0 && ele.css(prop_display) != 'none' ? ele : ele_management_table_container;
                            if (ele.length > 0 && ele.css(prop_display) != 'none') {
                                ele.css(prop_marginTop, 0);
                                var b_h = 30 + $(ele).offset().top - $(ele_filter_section).offset().top;
                                ele_filter_bubble_section.css(prop_marginTop, b_h);
                                $(ele).css(prop_marginTop, $(ele_filter_bubble_section).height() + 45);
                            } else {
                                ele_filter_bubble_section.css(prop_marginTop, 74);
                            }
                        } else {
                            if (!IsMobileView() && ele_mobile_always_filter.length <= 0) {
                                const bubbleSectionSpace = ele_artist_filter_save.length > 0 ? 11 : 0;
                                const distanceFromFilterContainer = 35; //Excluding bubble section height and splace
                                var b_h = 30 + bubbleSectionSpace + ele_bubble_placed_to.offset().top - ele_filter_section.offset().top;
                                if (IsPage(page_artwork_similar)) {
                                    ele_filter_bubble_section.css(prop_marginTop, b_h - 57);
                                    //ele_filters_card.css(prop_marginTop, ele_filter_bubble_section.height() + ele_compared_lot.height() + 45);
                                }
                                else {
                                    ele_filter_bubble_section.css(prop_marginTop, IsPage("exhibitionsearchresults") ? b_h - 30 : b_h);
                                    ele_filters_card.css(prop_marginTop, ele_filter_bubble_section.height() + 45 + bubbleSectionSpace);
                                }
                                ele_bubble_placed_to.css(prop_marginTop, ele_filter_bubble_section.height() + 45 + bubbleSectionSpace);
                                if (IsPage("exhibitionsearchresults") && $('.find-exhibitions-switch').css(prop_display) == 'none') {
                                    ele_dashboard_list.css(prop_marginTop, ele_filter_bubble_section.height() + 50 + bubbleSectionSpace + (ele_artist_filter_save.length > 0 ? distanceFromFilterContainer : 50));
                                } else {
                                    ele_dashboard_list.css(prop_marginTop, ele_filter_bubble_section.height() + bubbleSectionSpace + (ele_artist_filter_save.length > 0 ? distanceFromFilterContainer : 50));
                                }
                            }
                            else {
                                if (ele_dashboard_list.length > 0) {
                                    if (IsPage(artworks_for_sale_page)) {
                                        ele_dashboard_list.css(prop_marginTop, ele_filter_bubble_section.height() + 20);
                                        if (IsMobileView()) {
                                            const filterBtnHeight = $('.filters-header-mobile > .open-filters').outerHeight(true);
                                            const margin = 16;
                                            ele_filter_bubble_section.css(prop_marginTop, filterBtnHeight + margin);
                                            $('.filters-header-mobile > .resultsSpan').css('top', filterBtnHeight + ele_filter_bubble_section.height() + margin);
                                        } else {
                                            let h_r = ele_dashboard_list.offset().top - ele_filter_bubble_section.offset().top;
                                            h_r -= ele_filter_bubble_section.height();
                                            if (ele_artist_filter_save.length > 0) {
                                                h_r += ele_artist_filter_save.css(prop_display) == 'block' ? 0 : ele_artist_filter_save.height()
                                            }
                                            ele_filter_bubble_section.css(prop_marginTop, h_r);
                                        }
                                    }
                                    else {
                                        const filterText = $('.filter-state-text');
                                        const filterTitleTop = $('.filter-title-top');
                                        let h_r = 0;
                                        if (filterTitleTop.length > 0) h_r = filterTitleTop.height() + 18;

                                        const dashboardFiltersText = $('#dashTabs .filters-text');
                                        if (dashboardFiltersText.length > 0) h_r += dashboardFiltersText.height() + 30;

                                        ele_filter_bubble_section.css(prop_marginTop, $('.filters-header-mobile > .open-filters').outerHeight(true) + 16 + h_r);
                                        $(".results-wrapper").css(prop_marginTop, filterText.height() + ele_filter_bubble_section.height() + 12);
                                    }
                                } else if ($('.results-wrapper').length > 0) {
                                    $('.results-wrapper').css(prop_marginTop, ele_filter_bubble_section.height() + 20);
                                    var h_r = $('.results-wrapper').offset().top - ele_filter_bubble_section.offset().top;
                                    h_r -= ele_filter_bubble_section.height();
                                    if (ele_artist_filter_save.length > 0) {
                                        h_r += ele_artist_filter_save.css(prop_display) == 'block' ? 0 : ele_artist_filter_save.height()
                                    }
                                    ele_filter_bubble_section.css(prop_marginTop, h_r);
                                }
                            }
                        }
                    }
                }
                //else if (IsPage(page_artwork_similar)) {
                //    ele_filters_card.css(prop_marginTop, ele_filter_bubble_section.height() + (IsMobileView() ? 0 : ele_compared_lot.height() + 45));
                //}
                else if (IsPage('exhibitionsearchresults_browsemap')) {
                    if ($('#filters-container-tags > .tags-list').children('div').length > 0) {
                        $('#filters-container-tags').removeClass('hidden');
                    }
                    else {
                        $('#filters-container-tags').addClass('hidden');
                    }
                }

                $(".result-filter-panel").children('div').eq(1)
                    .css("top", -($(".filter-wrapper").height() + ele_filter_bubble_section.height() + (ele_filter_bubble_section.height() > 0 ? 0 : -10)))
                    .css("right", -7);
                const query = window.location.href.split('?')[1];
                const queryData = query && query.split('&');
                $(".result-filter-panel").css("top", manager.getSearchQueryList().length > 0 ? -48 : -22);
            }
            //setMobileHeaderText();
        },

        openSpecificFilter: function (e) {
            var selectedModule = manager.getModulesByQueryString(e.currentTarget.dataset['tagType']);
            if (selectedModule && selectedModule.length > 0) {
                if (selectedModule[0]._elem.hasClass('filter-sort')) {
                    selectedModule[0]._elem.find('ul').addClass('active');
                } else {
                    const collapsableTitle = selectedModule[0]._elem.closest('.collapsable-title');
                    const filterTab = collapsableTitle.find('span:first');
                    closeFilterBoxSize();
                    collapsableTitle.removeClass('collapsed');
                    SetCardSize();
                    manager.checkPageHeightForFilterBox();
                    manager.ToggleFilterControls(true);

                    sendFilterTabMixpanelEvent(filterTab);
                }
            }
        }
    };
}

function setMobileHeaderText() {
    const filtersMobileText = $(".filters-mobile-text");
    if (filtersMobileText.length > 0) {
        if (IsMobileView())
            filtersMobileText.css("position", "")
                .css("max-width", "").css("top", "")
                .css("left", "").css("padding", "");
        else {
            const mobileFiltersContainerBody = $(".mobile-filters-container-body");
            filtersMobileText.css("top", (mobileFiltersContainerBody.offset() && mobileFiltersContainerBody.offset().top) + mobileFiltersContainerBody.height() + 10)
                .css("position", "absolute")
                .css("max-width", mobileFiltersContainerBody.width())
                .css("left", mobileFiltersContainerBody.offset() && mobileFiltersContainerBody.offset().left)
                .css("padding", "initial")
                .css("display", "block");
        }
    }
}
function refreshResultOverride(m) {
    refreshResult(null, null);
}
function onFilterDoneClick(e) {
    var isBackdropclicked = e && e.target &&
        $(e.target).hasClass("modal-backdrop-ma");

    var forceCheck = e && e.target && $(e.target).hasClass("force-check");

    if ((manager.getQuery() != window.location.href && !isBackdropclicked) || forceCheck) {
        if (forceCheck && $(e.target).hasClass("remove-force-check")) {
            $(e.target).removeClass('force-check remove-force-check');
        }

        if (IsPage('my_collection/artisttrends')) {
            COMS.OnActionFilter();
        }
        else if (IsPage('artist_graphs')) {
            manager.setQuery('');
            manager.setFilterBedges();
            if (loadArtistPerfomanceSaleChartNew)
                loadArtistPerfomanceSaleChartNew();
            if (loadArtistSaleBreakdown)
                loadArtistSaleBreakdown();
            if (loadArtistPerformanceCountryWiseTotalSales)
                loadArtistPerformanceCountryWiseTotalSales();
            if (loadArtistLotBandDistribution)
                loadArtistLotBandDistribution();
            if (loadArtistPerfomanceAvgIndexChart)
                loadArtistPerfomanceAvgIndexChart();
            if (loadArttistPerfomanceIndexChart)
                loadArttistPerfomanceIndexChart();
            if (loadArtistPerformanceTopSoldLotsperYearChart)
                loadArtistPerformanceTopSoldLotsperYearChart();
        }
        else if (IsPage('analyticshub_artistperformance') || IsPage('analyticshub_performanceatauction')) {
            refreshHubResult();
            $("#close_filter_controls").click();
        }
        else if (window['onManagementFilter'])
            window['onManagementFilter']()

        else if (IsPage('exhibitionsearchresults_browsemap')) {
            triggerApplyExhibitionSearch();
        }
        else if (IsPage('exhibitionsearchresults')) {
            triggerApplyExhibitionSearch();
        }
        else
            refreshResult(null, window['onLoadMasonryImages']);

        if (e && e.target) {
            EmitEvent('onApplyFilter', {}, e.target);
        }
    }
    else if (manager.getQuery() != window.location.href) {
        UncheckDefaultPreferences();
        manager.loadQuery();
    }

    closeFilterBoxSize();
    manager.ToggleFilterControls(false);
    manager.checkPageHeightForFilterBox();
    $('.filters-card').find('.action-done').css('pointer-events', 'auto');

    setTimeout(setCollectionAlbumModalText, 100);
};

function setCollectionAlbumModalText() {
    if (IsPage("my_collection/albums")) {
        $('.collection-album-modal .theme-checkers:first-child').children('.text').text(manager.hasQuery() ? 'Select all works' : 'Select entire collection');
    }
}

function refreshHubResult(module, target) {
    if ($(".filter-controls.active").length && $("#executeFilter").length && $("#executeFilter").css("display") != 'none' && target != 'execute')
        return;
    if (getParameterByName("artistID"))
        var extraParams = 'artistID=' + getParameterByName("artistID");

    filtersSelectQueue.push(function () {
        // modules params
        manager.setQuery(extraParams);
        manager.setFilterBedges();
        //Ajax load all containers that begin with ajaxcontainer-
        var $ajxLoaders = $('[class^="ajaxcontainer-"], [class*=" ajaxcontainer-"]');
        if ($ajxLoaders.length > 0) {
            $ajxLoaders.each(function (index, element) {
                AjaxLoadContent(this, null, ($(".tab-content.active .chart-container").length && $ajxLoaders.length - 1 == index) || $(".auction-venue-results").length ? MA.CurrentAnalyticsHubModule.ReloadCharts : MA.CurrentAnalyticsHubModule.isFirstLoad);
            });
        } else if ($(".tab-content.active .chart-container").length || ($(".tab-content").length === 0 && $(".chart-container").length)) {
            MA.CurrentAnalyticsHubModule.ReloadCharts();
        }
        TraceSearch();
    });

    setTimeout(function () {
        if (filtersSelectQueue.length > 0) {
            filtersSelectQueue.pop()();
            filtersSelectQueue = [];
        }
    }, 500);
}

function populateFilterBedges() {
    if (IsPage('my_collection/artisttrends') || IsPage('my_collection/album') || IsPage('my_collection/albums')) {
        LoadChartTags();
        return;
    }

    var parentEle = undefined;
    if (IsPage('exhibitionsearchresults_browsemap')) {
        parentEle = $('#filters-container-tags > .tags-list');
    }
    //createSaveFilterBedge("saveFilter", "menu", "Save Filter");
    var queryData = window.location.href.split('?')[1].split('&');
    $.each(queryData, function (key, value) {
        var q_name = value.split('=')[0];
        var selectedModule = manager.getModulesByQueryString(q_name);
        if (selectedModule && selectedModule.length > 0) {
            var isAdditionalQuery = selectedModule[0]._AdditionalQueryName === q_name;
            if (isAdditionalQuery) {
                var queryKeys = queryData.map(param => param.split('=')[0]); 
                var isModuleLoadedAlready = queryKeys.includes(selectedModule[0]._queryName);
                if (isModuleLoadedAlready) return true;
            }
            selectedModule[0].renderSelectedBedges(parentEle);
        }
    });

    if ($('.artist-filter-save').length > 0 && manager.getSearchQueryList().length > 0) {
        const notAppliedEnoughFilters = manager.hasQuery() && manager.upcomingFilterQueryCount() < 2;
        const upcomingLotFilter = IsPage('auction_search') && notAppliedEnoughFilters;
        const isShowSigninPopup = IsPage('auction_search') && !notAppliedEnoughFilters && !isLoggedIn();
        const saveBtnStyle = `background-color:${upcomingLotFilter ? 'gray' : '#131721'}`;
        const saveBtnClasses = `btn-cta forms save-filter tooltip-lg ${isShowSigninPopup ? 'popup' : ''}`;
        const toolTip = upcomingLotFilter ? `data-toggle='tooltip' title="To get an Alert for this filter, you have to use at least 2 of these: Artist Nationality, Artwork Title, Media Category, Medium Text, Creation Year, Height, Width, or Sale Title." data-placement="bottom"` : ``;
        const clickEvent = upcomingLotFilter || isShowSigninPopup ? `` : `ArtistModule.open_step_three()`;
        const signinPopupQuery = isShowSigninPopup ? `data-id='signupForm' data-query='showNewSignUp=true'` : ``;
        $(".filter-bubble-section").append(`
            <div class="btn-group margin-bottom-15">
                <a onclick="${clickEvent}" class="${saveBtnClasses}" ${toolTip} style="${saveBtnStyle}" ${signinPopupQuery}>  
                    ${IsPage('auction_search') ? 'FOLLOW FILTER' : 'SAVE FILTER'}
                </a>
            </div>
        `);
        $(".save-filter").tooltip();
    }

    if (IsPage('exhibitionsearchresults_browsemap')) {
        if ($('#filters-container-tags > .tags-list').children().length > 0) {
            $('#filters-container-tags ').removeClass('hidden');
        }
        else {
            $('#filters-container-tags ').addClass('hidden');
        }
    }
}
function createSaveFilterBedge(key, type, text) {
    const saveFilterTemplate = `
            <div class="btn-group margin-bottom-10 bubble-button-group" data-val="${key}" data-tag-type="${type}">
                <button type="button" style="border-radius: 25px" class="btn btn-black btn-pill btn-bubble btn-openSaveFilter">${text}</button>
                <div class="filter_save_popup_wrap hidden">
                    <div class="filter_save_step_title filter_save_popup_title hidden">
                        <span class="close_filter_popup" onclick="ArtistModule.close_filter_popup()">x</span>
                        Save the filter to receive alerts every time its status changes
                    </div>
                    <div class="filter_save_step_3 save_filter hidden">
                        <span class="save_filter_btn" onclick="ArtistModule.open_step_four()">SAVE FILTER</span>
                        <span class="save_filter_edit"></span>
                        <input class="save_filter_name" placeholder="Art name Upcoming+sold" type="text" />
                    </div>
                    <div class="filter_save_step_4 save_filter hidden">
                        <span class="save_filter_btn">SAVED</span>
                        <span class="save_filter_edit filter_edit filter_saved"></span>
                        <input class="save_filter_name filter_edit" placeholder="Art name Upcoming+sold" type="text" disabled />
                    </div>
                </div>
            </div>
        `;

    $(".filter-bubble-section").append(saveFilterTemplate);
}

function createBedge(key, type, text, parentEle) {
    if (text) {
        if (parentEle) {
            $(parentEle).append(`
            <div class="btn-group margin-bottom-15 bubble-button-group" data-val="${key}" data-tag-type="${type}">
              <button type="button" class="btn btn-gray btn-pill btn-bubble btn-select-bubble">${text}</button>
              <button type="button" class="btn btn-gray btn-pill btn-bubble btn-remove-bubble"><i class="m-icon-menu-close bold"></i></a></button>
            </div>
        `);
        }
        else {
            $(".filter-bubble-section").append(`
            <div class="btn-group margin-bottom-15" data-val="${key}" data-tag-type="${type}">
              <button type="button" class="btn btn-gray btn-pill btn-bubble btn-select-bubble">${text}</button>
              <button type="button" class="btn btn-gray btn-pill btn-bubble btn-remove-bubble"><i class="m-icon-menu-close bold"></i></a></button>
            </div>
        `);
        }
    }
}

function LoadChartTags() {
    var modules = manager.modules();
    for (var ind in modules) {
        if (modules[ind] instanceof tagsModule) {
            modules[ind].bindData();
        }
    }
}

function SetCardSize() {
    if ($(".tooltip").length > 0) {
        $(".tooltip").tooltip("hide");
    }
    if (!IsMobileView() && !$('body').hasClass('mobile-always-filter') && $('.filter-section').length > 0) {
        $('.filters-card').css('width', $('.results-wrapper:not(.display-none)').width() - 6);
        if (IsPage('exhibitionsearchresults_browsemap') && $('.results-wrapper:not(.display-none)').width() > 820) {
            $('.filters-card').css('width', '814px');
        }

        var windowHeight = window.innerHeight - 236;
        windowHeight = windowHeight - $("#ma-navigation .nav-header").height();
        windowHeight = windowHeight - ($('.artist-top-nav').length > 0 ? $('.artist-top-nav').height() : 0);
        windowHeight = windowHeight - ($('#hub-main-nav').length > 0 ? $('#hub-main-nav').height() : 0);
        windowHeight = windowHeight - (IsPage('artwork_similar') ? -3 : 0);
        $('.sale-outcome').css('height', windowHeight);

        if ($('.filters-card').height() < 573 && $('.collapsable-title:not(.collapsed)').length > 0) {
            $('.mobile-filters-container-body-secondary').css('height', $('.filters-card').height()).css('overflow', 'auto').addClass('module-scrollbar-thin');
        } else {
            $('.mobile-filters-container-body-secondary').css('height', '').css('overflow', '').removeClass('module-scrollbar-thin');
            if (IsPage('artwork_similar')) {
                $("#compare-lot").show();
            }
        }

        if ($('.collapsable-title:not(.collapsed)').length > 0) {
            $('.filters-card').css('marginTop', ($('.filter-bubble-section').height() > 0 ? $('.filter-bubble-section').height() + 44 : 0));
            if (IsPage('artwork_similar')) {
                $("#compare-lot").hide();
            }
            //MAPF-9385 Scroll hide/show issue when open filter
            //Reset CSS due to multiple calls
            $('body').css('top', '');
            $('body').removeClass('open-filter-card ');

            if (IsPage('artist_auctionresults')) {
                setMobileHeaderText();
            }
            if (IsPage('exhibitionsearchresults_browsemap')) {
                $('#exhibitions-switch-map').addClass('display-none');
            }

            var scrollY = $('.collapsable-title').first().offset().top;
            bodyTop = scrollY - ($('#ma-navigation:not(.collection-navigation) .nav-header').outerHeight() +
                $('.menu-sticky-wrapper').outerHeight() + $('.collection-tab-navigation').outerHeight() + 15); 

            if (IsPage('exhibitionsearchresults_browsemap') &&  (!$('#filters-container-tags').hasClass('hidden'))) {
                    bodyTop = bodyTop - ($('#filters-container-tags').outerHeight() + 35);
            }

            $('head').addClass('filter-overflow-y');
            $('body').addClass('open-filter-card');
            $('body').css('top', `-${bodyTop}px`,);


            var analyticspages = ['analyticshub_artistperformance', 'analyticshub_performanceatauction'];
            if (analyticspages.includes(page_name)) {
                $([document.documentElement, document.body]).animate({
                    scrollTop: $(".mobile-filters-container-body-secondary").offset().top - (120 + (window.innerHeight > 687 ? 20 : 0))
                }, 0, setNavigation);
            }
            else if (IsPage('my_collection/artisttrends')) {
                $([document.documentElement, document.body]).animate({
                    scrollTop: $('.filter-wrapper .collapsable-title:first').offset().top - 100
                }, 0, setNavigation);
            }
            //else if (IsPage('artwork_similar')) {
            //    $([document.documentElement, document.body]).animate({
            //        scrollTop: $(".mobile-filters-container-body-secondary").offset().top - 120
            //    }, 0, setNavigation);
            //}
            else {
                $([document.documentElement, document.body]).animate({
                    scrollTop: $('.artist-top-nav').length > 0 || $('.sticky-analytics-header').length > 0
                        ? $(".mobile-filters-container-body-secondary").offset().top - 120
                        : $(".mobile-filters-container-body-secondary").offset().top - 85
                }, 0, setNavigation);
            }
        } else {
            var toScroll = $('body').hasClass('open-filter-card');
            $('head').removeClass('filter-overflow-y');
            $('body').css('top', '');
            $('body').removeClass('open-filter-card');
            if (toScroll)
            {
                var scrollY = $('.collapsable-title').first().offset().top;
                bodyTop = scrollY - ($('#ma-navigation:not(.collection-navigation) .nav-header').outerHeight() +
                    $('.menu-sticky-wrapper').outerHeight() + $('.collection-tab-navigation').outerHeight() + 15); 

                window.scrollTo(0, bodyTop);
            }
            if (IsPage('artist_auctionresults')) {
                setMobileHeaderText()
            }
            if (IsPage('exhibitionsearchresults_browsemap')) {
                $('#ma-navigation').removeClass('collapsed');
            }
            $('#exhibitions-switch-map').removeClass('display-none');
        }
    }
    else {
        $('.filters-card').css('width', '');
        $('.sale-outcome').css('height', '');
    }
}

function setNavigation() {
    setTimeout(function () {
        $('body').addClass('collapsed')
        $('#ma-navigation').addClass('collapsed');
    }, 100)
}

function closeFilterBoxSize() {
    $('.collapsable-title').addClass("collapsed");
    SetCardSize();
}

function UpdateUserDefaultPreference(eleApply) {
    let ele = $(eleApply.target).parents('.filters-card').find('.filters-card-body .save-as-default-preference');
    if (ele && ele.is(":checked")) {
        let parentEle = ele.closest('.default-currency-block').parent().find('.badges-filter-block');
        let selectedEle = ele.closest('.default-currency-block').parent().find('.badges-filter-block a.selected');
        let applyFilterEle = ele.parents('.filters-card-body').siblings(".filters-card-footer").find('.action-done');

        if (selectedEle && parentEle) {
            let selectedId = selectedEle.data('id');
            let existingId = parentEle.attr('data-initial-value');
            let validateBeforeSave = ele.data('validateBeforeSave');

            if (validateBeforeSave ? selectedId !== existingId : validateBeforeSave === false) {
                $.post("/Ajax/account_settings/UpdateUserDefaultPreference", {
                    value: selectedId,
                    key: ele.data('preferenceType')
                }, function (rText, status, request) {
                    ele.prop("checked", false);
                    applyFilterEle.addClass('force-check remove-force-check dont-track-callback');
                    ele.closest('.checkbox-container').addClass('tooltip-hidden');

                    parentEle.attr('data-initial-value', selectedId);
                    ele.closest('.default-currency-block').addClass('hidden');
                    
                    onFilterDoneClick(eleApply);
                }).fail(function () {
                    ele.prop("checked", false);
                });
            }
            else {
                ele.prop("checked", false);
            }
        }
    }
}

function UncheckDefaultPreferences() {
    $(".save-as-default-preference").each(function (index) {
        var ele = $(this);
        if (ele.is(":checked")) {
            ele.prop('checked', false);
        }
    });
}

function SetActiveFilterFlag() {
    $('.collapsable-title span.filter-flag').removeClass('active');
    var modules = manager.modules();
    for (var i = 0; i < modules.length; i++) {
        var current = modules[i];
        var hasSearchAll = current.searchAll && current.getAdditionalSelected && current.getAdditionalSelected() !== ""; // checklistAddToListModule module

        if (!current._queryName)
            continue;
        if (!hasSearchAll && (current.getSelected() == null || (!current._sendEmptyValue && (!current.isPopulated() || current.getSelected() == "")))) {

            continue;
        }
        current._elem.closest('.collapsable-title').find('.filter-flag').addClass('active');
    }
} ;
function SaveSearchModule(elem) {
    var self = this;
    self._elem = $(elem);
    var savedFilters = {};
    var curPath = "";
    var NOTSAVED_TEXT = 'Save and add search to my daily mail';
    var SAVED_TEXT = 'Saved and added';
    var init = function () {
        window.addEventListener("moduleQueryChange", onModuleQueryChange);

        self._elem.on("click",".bookmark-animation, .bookmark-text", onToggleBookmark)
        //self._elem.tooltip({ allowHover: true });

        return _export;
    }
    

    function onModuleQueryChange(e) {
        curPath = window.location.pathname + e.detail.Qs;
        if (e.detail.queryCount > 0) {
            self._elem.show();
        }
        if (savedFilters[curPath]) {
            self._elem.find(".bookmark-animation").addClass("active");
            self._elem.find(".bookmark-text").text(SAVED_TEXT);
        } else {
            self._elem.find(".bookmark-animation").removeClass("active");
            self._elem.find(".bookmark-text").text(NOTSAVED_TEXT);
        }
    }
    function getFilterTitle() {
        if (location.pathname.toLowerCase().startsWith("/artist/"))
            return "Artist, At Auction";
        if (location.pathname.toLowerCase().startsWith("/buy_art"))
            return "Upcoming Lot Search";
        return "Auction Lot Search";
    }
    function onToggleBookmark(e) {
        self._elem.find(".bookmark-animation").toggleClass("active");
        var toActive = self._elem.find(".bookmark-animation").hasClass("active");
        if (toActive) {
            self._elem.find(".bookmark-text").text(SAVED_TEXT);
            createNewFilter();
        } else {
            self._elem.find(".bookmark-text").text(NOTSAVED_TEXT);
            removeFilter();
        }
    }
    function removeFilter() {
        $.ajax({
            method: 'DELETE',
            url: '/api/dashboard/filter',
            dataType: "json",
            data: {
                title: getFilterTitle(),
                path: curPath
            },
            success: function (data) {
                if (data.OK == true) {
                    GTM_Send('event', 'save', 'search', curPath);
                    delete savedFilters[curPath];
                }
                else {
                    self._elem.find(".bookmark-animation").toggleClass("active");
                }
            }
        });
    }
    function createNewFilter() {
        $.ajax({
            method: 'POST',
            url: '/api/dashboard/filter',
            dataType: "json",
            data: {
                title: getFilterTitle(),
                path: curPath
            },
            success: function (data) {
                if (data.OK == true) {
                    GTM_Send('event', 'save', 'search', curPath);
                    savedFilters[curPath] = true;
                }
                else {
                    self._elem.find(".bookmark-animation").toggleClass("active");
                    //maAlertMessage(data.Message, ["OK"], function () { })
                }
            }
        });

    }

    var _export = {
        name: "SaveSearchModule",
        init: init
    };

    return _export;
};
