var $ = jQuery;
/*
 * Variables
 */
var $apiUri = '/api/';
var animate_prefix = '';

var $btnScrollTop = ['<a href="#" class="scrollToTop" title="Scroll to top"></a>'];
var $btnScrollTopSelector = '.scrollToTop';

var dtb_language = {
	decimal:			"",
	emptyTable:			"Keine Daten in Tabelle verfügbar",
	info:				"_START_ bis _END_ von _TOTAL_ Einträgen anzeigen",
	infoEmpty:			"0 bis 0 von 0 Einträgen anzeigen",
	infoFiltered:		"(gefiltert aus _MAX_ Gesamteinträgen)",
	infoPostFix:		"",
	thousands:			",",
	lengthMenu:			"_MENU_ Einträge anzeigen",
	loadingRecords:		"Loading...",
	processing:			"Processing...",
	search:				"Suche:",
	zeroRecords:		"Keine übereinstimmenden Datensätze gefunden",
	paginate: {
		first:			'<i class="fas fa-angle-double-right"></i>',
		last:			'<i class="fas fa-angle-double-left"></i>',
		next:			'<i class="fas fa-angle-right"></i>',
		previous:		'<i class="fas fa-angle-left"></i>'
	},
	aria: {
		sortAscending:	": aktivieren, um die Spalte aufsteigend zu sortieren",
		sortDescending:	": aktivieren, um die absteigende Spalte zu sortieren"
	}
};

/*!
 * jQuery.scrollTo
 * Copyright (c) 2007-2015 Ariel Flesler - aflesler<a>gmail<d>com | http://flesler.blogspot.com
 * Licensed under MIT
 * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
 * @projectDescription Lightweight, cross-browser and highly customizable animated scrolling with jQuery
 * @author Ariel Flesler
 * @version 2.1.2
 */
;(function(factory) {
	'use strict';
	if (typeof define === 'function' && define.amd) {
		// AMD
		define(['jquery'], factory);
	} else if (typeof module !== 'undefined' && module.exports) {
		// CommonJS
		module.exports = factory(require('jquery'));
	} else {
		// Global
		factory(jQuery);
	}
})(function($) {
	'use strict';

	var $scrollTo = $.scrollTo = function(target, duration, settings) {
		return $(window).scrollTo(target, duration, settings);
	};

	$scrollTo.defaults = {
		axis:'xy',
		duration: 0,
		limit:true
	};

	function isWin(elem) {
		return !elem.nodeName ||
			$.inArray(elem.nodeName.toLowerCase(), ['iframe','#document','html','body']) !== -1;
	}

	$.fn.scrollTo = function(target, duration, settings) {
		if (typeof duration === 'object') {
			settings = duration;
			duration = 0;
		}
		if (typeof settings === 'function') {
			settings = { onAfter:settings };
		}
		if (target === 'max') {
			target = 9e9;
		}

		settings = $.extend({}, $scrollTo.defaults, settings);
		// Speed is still recognized for backwards compatibility
		duration = duration || settings.duration;
		// Make sure the settings are given right
		var queue = settings.queue && settings.axis.length > 1;
		if (queue) {
			// Let's keep the overall duration
			duration /= 2;
		}
		settings.offset = both(settings.offset);
		settings.over = both(settings.over);

		return this.each(function() {
			// Null target yields nothing, just like jQuery does
			if (target === null) return;

			var win = isWin(this),
				elem = win ? this.contentWindow || window : this,
				$elem = $(elem),
				targ = target,
				attr = {},
				toff;

			switch (typeof targ) {
				// A number will pass the regex
				case 'number':
				case 'string':
					if (/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)) {
						targ = both(targ);
						// We are done
						break;
					}
					// Relative/Absolute selector
					targ = win ? $(targ) : $(targ, elem);
				/* falls through */
				case 'object':
					if (targ.length === 0) return;
					// DOMElement / jQuery
					if (targ.is || targ.style) {
						// Get the real position of the target
						toff = (targ = $(targ)).offset();
					}
			}

			var offset = $.isFunction(settings.offset) && settings.offset(elem, targ) || settings.offset;

			$.each(settings.axis.split(''), function(i, axis) {
				var Pos	= axis === 'x' ? 'Left' : 'Top',
					pos = Pos.toLowerCase(),
					key = 'scroll' + Pos,
					prev = $elem[key](),
					max = $scrollTo.max(elem, axis);

				if (toff) {// jQuery / DOMElement
					attr[key] = toff[pos] + (win ? 0 : prev - $elem.offset()[pos]);

					// If it's a dom element, reduce the margin
					if (settings.margin) {
						attr[key] -= parseInt(targ.css('margin'+Pos), 10) || 0;
						attr[key] -= parseInt(targ.css('border'+Pos+'Width'), 10) || 0;
					}

					attr[key] += offset[pos] || 0;

					if (settings.over[pos]) {
						// Scroll to a fraction of its width/height
						attr[key] += targ[axis === 'x'?'width':'height']() * settings.over[pos];
					}
				} else {
					var val = targ[pos];
					// Handle percentage values
					attr[key] = val.slice && val.slice(-1) === '%' ?
						parseFloat(val) / 100 * max
						: val;
				}

				// Number or 'number'
				if (settings.limit && /^\d+$/.test(attr[key])) {
					// Check the limits
					attr[key] = attr[key] <= 0 ? 0 : Math.min(attr[key], max);
				}

				// Don't waste time animating, if there's no need.
				if (!i && settings.axis.length > 1) {
					if (prev === attr[key]) {
						// No animation needed
						attr = {};
					} else if (queue) {
						// Intermediate animation
						animate(settings.onAfterFirst);
						// Don't animate this axis again in the next iteration.
						attr = {};
					}
				}
			});

			animate(settings.onAfter);

			function animate(callback) {
				var opts = $.extend({}, settings, {
					// The queue setting conflicts with animate()
					// Force it to always be true
					queue: true,
					duration: duration,
					complete: callback && function() {
						callback.call(elem, targ, settings);
					}
				});
				$elem.animate(attr, opts);
			}
		});
	};

	// Max scrolling position, works on quirks mode
	// It only fails (not too badly) on IE, quirks mode.
	$scrollTo.max = function(elem, axis) {
		var Dim = axis === 'x' ? 'Width' : 'Height',
			scroll = 'scroll'+Dim;

		if (!isWin(elem))
			return elem[scroll] - $(elem)[Dim.toLowerCase()]();

		var size = 'client' + Dim,
			doc = elem.ownerDocument || elem.document,
			html = doc.documentElement,
			body = doc.body;

		return Math.max(html[scroll], body[scroll]) - Math.min(html[size], body[size]);
	};

	function both(val) {
		return $.isFunction(val) || $.isPlainObject(val) ? val : { top:val, left:val };
	}

	// Add special hooks so that window scroll properties can be animated
	$.Tween.propHooks.scrollLeft =
		$.Tween.propHooks.scrollTop = {
			get: function(t) {
				return $(t.elem)[t.prop]();
			},
			set: function(t) {
				var curr = this.get(t);
				// If interrupt is true and user scrolled, stop animating
				if (t.options.interrupt && t._last && t._last !== curr) {
					return $(t.elem).stop();
				}
				var next = Math.round(t.now);
				// Don't waste CPU
				// Browsers don't render floating point scroll
				if (curr !== next) {
					$(t.elem)[t.prop](next);
					t._last = this.get(t);
				}
			}
		};

	// AMD requirement
	return $scrollTo;
});

/*
 * Toastr
 * Copyright 2012-2015
 * Authors: John Papa, Hans Fjällemark, and Tim Ferrell.
 * All Rights Reserved.
 * Use, reproduction, distribution, and modification of this code is subject to the terms and
 * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
 *
 * ARIA Support: Greta Krafsig
 *
 * Project: https://github.com/CodeSeven/toastr
 */
/* global define */
(function (define) {
	define(['jquery'], function ($) {
		return (function () {
			var $container;
			var listener;
			var toastId = 0;
			var toastType = {
				error: 'error',
				info: 'info',
				success: 'success',
				warning: 'warning'
			};

			var toastr = {
				clear: clear,
				remove: remove,
				error: error,
				getContainer: getContainer,
				info: info,
				options: {},
				subscribe: subscribe,
				success: success,
				version: '2.1.4',
				warning: warning
			};

			var previousToast;

			return toastr;

			////////////////

			function error(message, title, optionsOverride) {
				return notify({
					type: toastType.error,
					iconClass: getOptions().iconClasses.error,
					message: message,
					optionsOverride: optionsOverride,
					title: title
				});
			}

			function getContainer(options, create) {
				if (!options) { options = getOptions(); }
				$container = $('#' + options.containerId);
				if ($container.length) {
					return $container;
				}
				if (create) {
					$container = createContainer(options);
				}
				return $container;
			}

			function info(message, title, optionsOverride) {
				return notify({
					type: toastType.info,
					iconClass: getOptions().iconClasses.info,
					message: message,
					optionsOverride: optionsOverride,
					title: title
				});
			}

			function subscribe(callback) {
				listener = callback;
			}

			function success(message, title, optionsOverride) {
				return notify({
					type: toastType.success,
					iconClass: getOptions().iconClasses.success,
					message: message,
					optionsOverride: optionsOverride,
					title: title
				});
			}

			function warning(message, title, optionsOverride) {
				return notify({
					type: toastType.warning,
					iconClass: getOptions().iconClasses.warning,
					message: message,
					optionsOverride: optionsOverride,
					title: title
				});
			}

			function clear($toastElement, clearOptions) {
				var options = getOptions();
				if (!$container) { getContainer(options); }
				if (!clearToast($toastElement, options, clearOptions)) {
					clearContainer(options);
				}
			}

			function remove($toastElement) {
				var options = getOptions();
				if (!$container) { getContainer(options); }
				if ($toastElement && $(':focus', $toastElement).length === 0) {
					removeToast($toastElement);
					return;
				}
				if ($container.children().length) {
					$container.remove();
				}
			}

			// internal functions

			function clearContainer (options) {
				var toastsToClear = $container.children();
				for (var i = toastsToClear.length - 1; i >= 0; i--) {
					clearToast($(toastsToClear[i]), options);
				}
			}

			function clearToast ($toastElement, options, clearOptions) {
				var force = clearOptions && clearOptions.force ? clearOptions.force : false;
				if ($toastElement && (force || $(':focus', $toastElement).length === 0)) {
					$toastElement[options.hideMethod]({
						duration: options.hideDuration,
						easing: options.hideEasing,
						complete: function () { removeToast($toastElement); }
					});
					return true;
				}
				return false;
			}

			function createContainer(options) {
				$container = $('<div/>')
					.attr('id', options.containerId)
					.addClass(options.positionClass);

				$container.appendTo($(options.target));
				return $container;
			}

			function getDefaults() {
				return {
					tapToDismiss: true,
					toastClass: 'toast',
					containerId: 'toast-container',
					debug: false,

					showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
					showDuration: 300,
					showEasing: 'swing', //swing and linear are built into jQuery
					onShown: undefined,
					hideMethod: 'fadeOut',
					hideDuration: 1000,
					hideEasing: 'swing',
					onHidden: undefined,
					closeMethod: false,
					closeDuration: false,
					closeEasing: false,
					closeOnHover: true,

					extendedTimeOut: 1000,
					iconClasses: {
						error: 'toast-error',
						info: 'toast-info',
						success: 'toast-success',
						warning: 'toast-warning'
					},
					iconClass: 'toast-info',
					positionClass: 'toast-top-right',
					timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky
					titleClass: 'toast-title',
					messageClass: 'toast-message',
					escapeHtml: false,
					target: 'body',
					closeHtml: '<button type="button">&times;</button>',
					closeClass: 'toast-close-button',
					newestOnTop: true,
					preventDuplicates: false,
					progressBar: false,
					progressClass: 'toast-progress',
					rtl: false
				};
			}

			function publish(args) {
				if (!listener) { return; }
				listener(args);
			}

			function notify(map) {
				var options = getOptions();
				var iconClass = map.iconClass || options.iconClass;

				if (typeof (map.optionsOverride) !== 'undefined') {
					options = $.extend(options, map.optionsOverride);
					iconClass = map.optionsOverride.iconClass || iconClass;
				}

				if (shouldExit(options, map)) { return; }

				toastId++;

				$container = getContainer(options, true);

				var intervalId = null;
				var $toastElement = $('<div/>');
				var $titleElement = $('<div/>');
				var $messageElement = $('<div/>');
				var $progressElement = $('<div/>');
				var $closeElement = $(options.closeHtml);
				var progressBar = {
					intervalId: null,
					hideEta: null,
					maxHideTime: null
				};
				var response = {
					toastId: toastId,
					state: 'visible',
					startTime: new Date(),
					options: options,
					map: map
				};

				personalizeToast();

				displayToast();

				handleEvents();

				publish(response);

				if (options.debug && console) {
					console.log(response);
				}

				return $toastElement;

				function escapeHtml(source) {
					if (source == null) {
						source = '';
					}

					return source
						.replace(/&/g, '&amp;')
						.replace(/"/g, '&quot;')
						.replace(/'/g, '&#39;')
						.replace(/</g, '&lt;')
						.replace(/>/g, '&gt;');
				}

				function personalizeToast() {
					setIcon();
					setTitle();
					setMessage();
					setCloseButton();
					setProgressBar();
					setRTL();
					setSequence();
					setAria();
				}

				function setAria() {
					var ariaValue = '';
					switch (map.iconClass) {
						case 'toast-success':
						case 'toast-info':
							ariaValue =  'polite';
							break;
						default:
							ariaValue = 'assertive';
					}
					$toastElement.attr('aria-live', ariaValue);
				}

				function handleEvents() {
					if (options.closeOnHover) {
						$toastElement.hover(stickAround, delayedHideToast);
					}

					if (!options.onclick && options.tapToDismiss) {
						$toastElement.click(hideToast);
					}

					if (options.closeButton && $closeElement) {
						$closeElement.click(function (event) {
							if (event.stopPropagation) {
								event.stopPropagation();
							} else if (event.cancelBubble !== undefined && event.cancelBubble !== true) {
								event.cancelBubble = true;
							}

							if (options.onCloseClick) {
								options.onCloseClick(event);
							}

							hideToast(true);
						});
					}

					if (options.onclick) {
						$toastElement.click(function (event) {
							options.onclick(event);
							hideToast();
						});
					}
				}

				function displayToast() {
					$toastElement.hide();

					$toastElement[options.showMethod](
						{duration: options.showDuration, easing: options.showEasing, complete: options.onShown}
					);

					if (options.timeOut > 0) {
						intervalId = setTimeout(hideToast, options.timeOut);
						progressBar.maxHideTime = parseFloat(options.timeOut);
						progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
						if (options.progressBar) {
							progressBar.intervalId = setInterval(updateProgress, 10);
						}
					}
				}

				function setIcon() {
					if (map.iconClass) {
						$toastElement.addClass(options.toastClass).addClass(iconClass);
					}
				}

				function setSequence() {
					if (options.newestOnTop) {
						$container.prepend($toastElement);
					} else {
						$container.append($toastElement);
					}
				}

				function setTitle() {
					if (map.title) {
						var suffix = map.title;
						if (options.escapeHtml) {
							suffix = escapeHtml(map.title);
						}
						$titleElement.append(suffix).addClass(options.titleClass);
						$toastElement.append($titleElement);
					}
				}

				function setMessage() {
					if (map.message) {
						var suffix = map.message;
						if (options.escapeHtml) {
							suffix = escapeHtml(map.message);
						}
						$messageElement.append(suffix).addClass(options.messageClass);
						$toastElement.append($messageElement);
					}
				}

				function setCloseButton() {
					if (options.closeButton) {
						$closeElement.addClass(options.closeClass).attr('role', 'button');
						$toastElement.prepend($closeElement);
					}
				}

				function setProgressBar() {
					if (options.progressBar) {
						$progressElement.addClass(options.progressClass);
						$toastElement.prepend($progressElement);
					}
				}

				function setRTL() {
					if (options.rtl) {
						$toastElement.addClass('rtl');
					}
				}

				function shouldExit(options, map) {
					if (options.preventDuplicates) {
						if (map.message === previousToast) {
							return true;
						} else {
							previousToast = map.message;
						}
					}
					return false;
				}

				function hideToast(override) {
					var method = override && options.closeMethod !== false ? options.closeMethod : options.hideMethod;
					var duration = override && options.closeDuration !== false ?
						options.closeDuration : options.hideDuration;
					var easing = override && options.closeEasing !== false ? options.closeEasing : options.hideEasing;
					if ($(':focus', $toastElement).length && !override) {
						return;
					}
					clearTimeout(progressBar.intervalId);
					return $toastElement[method]({
						duration: duration,
						easing: easing,
						complete: function () {
							removeToast($toastElement);
							clearTimeout(intervalId);
							if (options.onHidden && response.state !== 'hidden') {
								options.onHidden();
							}
							response.state = 'hidden';
							response.endTime = new Date();
							publish(response);
						}
					});
				}

				function delayedHideToast() {
					if (options.timeOut > 0 || options.extendedTimeOut > 0) {
						intervalId = setTimeout(hideToast, options.extendedTimeOut);
						progressBar.maxHideTime = parseFloat(options.extendedTimeOut);
						progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
					}
				}

				function stickAround() {
					clearTimeout(intervalId);
					progressBar.hideEta = 0;
					$toastElement.stop(true, true)[options.showMethod](
						{duration: options.showDuration, easing: options.showEasing}
					);
				}

				function updateProgress() {
					var percentage = ((progressBar.hideEta - (new Date().getTime())) / progressBar.maxHideTime) * 100;
					$progressElement.width(percentage + '%');
				}
			}

			function getOptions() {
				return $.extend({}, getDefaults(), toastr.options);
			}

			function removeToast($toastElement) {
				if (!$container) { $container = getContainer(); }
				if ($toastElement.is(':visible')) {
					return;
				}
				$toastElement.remove();
				$toastElement = null;
				if ($container.children().length === 0) {
					$container.remove();
					previousToast = undefined;
				}
			}

		})();
	});
}(typeof define === 'function' && define.amd ? define : function (deps, factory) {
	if (typeof module !== 'undefined' && module.exports) { //Node
		module.exports = factory(require('jquery'));
	} else {
		window.toastr = factory(window.jQuery);
	}
}));

$(function() {
	var $offset = $('#navbarhead').height();

	$('body').append($btnScrollTop);

	$(window).scroll(function () {
		if($(this).scrollTop() > $offset) {
			$('#navbar-main').addClass('fixed-top');
			$('#navbar-main .navbar-brand').fadeIn(400);

			$($btnScrollTopSelector).fadeIn(400);
		} else {
			$('#navbar-main').removeClass('fixed-top');
			$('#navbar-main .navbar-brand').fadeOut(200);

			$($btnScrollTopSelector).fadeOut(600);
		}
	});

	$($btnScrollTopSelector).click(function (e) {
		e.preventDefault();

		$('body,html').animate({
			scrollTop: 0
		}, 800);
	});

	if($(window).scrollTop() > $offset) {
		$('#navbar-main').addClass('fixed-top');
		$('#navbar-main .navbar-brand').fadeIn(400);

		$($btnScrollTopSelector).fadeIn(400);
	} else {
		$('#navbar-main').removeClass('fixed-top');
		$('#navbar-main .navbar-brand').fadeOut(200);

		$($btnScrollTopSelector).fadeOut(600);
	}
});

document.addEventListener("DOMContentLoaded", function(){
	// make it as accordion for smaller screens
	if (window.innerWidth > 992) {
		document.querySelectorAll('.navbar .nav-item').forEach(function(everyitem) {
			everyitem.addEventListener('mouseover', function(e) {
				let el_link = this.querySelector('a[data-bs-toggle]');

				if (el_link != null) {
					let nextEl = el_link.nextElementSibling;
					el_link.classList.add('show');
					nextEl.classList.add('show');
				}
			});

			everyitem.addEventListener('mouseleave', function(e) {
				let el_link = this.querySelector('a[data-bs-toggle]');

				if (el_link != null) {
					let nextEl = el_link.nextElementSibling;
					el_link.classList.remove('show');
					nextEl.classList.remove('show');
				}
			});
		});
	}

	// make it as accordion for smaller screens
	if (window.innerWidth < 992) {
		// close all inner dropdowns when parent is closed
		document.querySelectorAll('.navbar .dropdown').forEach(function(everydropdown){
			everydropdown.addEventListener('hidden.bs.dropdown', function () {
				// after dropdown is hidden, then find all submenus
				this.querySelectorAll('.submenu').forEach(function(everysubmenu){
					// hide every submenu as well
					everysubmenu.style.display = 'none';
				});
			});
		});

		document.querySelectorAll('.dropdown-menu a').forEach(function(element){
			element.addEventListener('click', function (e) {
				let nextEl = this.nextElementSibling;

				if(nextEl && nextEl.classList.contains('submenu')) {
					// prevent opening link if link needs to open dropdown
					e.preventDefault();

					if(nextEl.style.display == 'block'){
						nextEl.style.display = 'none';
					} else {
						nextEl.style.display = 'block';
					}

				}
			});
		});
	}
	// end if innerWidth
});

/*!
 * Lightbox v2.11.3
 * by Lokesh Dhakar
 *
 * More info:
 * http://lokeshdhakar.com/projects/lightbox2/
 *
 * Copyright Lokesh Dhakar
 * Released under the MIT license
 * https://github.com/lokesh/lightbox2/blob/master/LICENSE
 *
 * @preserve
 */

// Uses Node, AMD or browser globals to create a module.
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals (root is window)
        root.lightbox = factory(root.jQuery);
    }
}(this, function ($) {

  function Lightbox(options) {
    this.album = [];
    this.currentImageIndex = void 0;
    this.init();

    // options
    this.options = $.extend({}, this.constructor.defaults);
    this.option(options);
  }

  // Descriptions of all options available on the demo site:
  // http://lokeshdhakar.com/projects/lightbox2/index.html#options
  Lightbox.defaults = {
    albumLabel: 'Image %1 of %2',
    alwaysShowNavOnTouchDevices: false,
    fadeDuration: 600,
    fitImagesInViewport: true,
    imageFadeDuration: 600,
    // maxWidth: 800,
    // maxHeight: 600,
    positionFromTop: 50,
    resizeDuration: 700,
    showImageNumberLabel: true,
    wrapAround: false,
    disableScrolling: false,
    /*
    Sanitize Title
    If the caption data is trusted, for example you are hardcoding it in, then leave this to false.
    This will free you to add html tags, such as links, in the caption.

    If the caption data is user submitted or from some other untrusted source, then set this to true
    to prevent xss and other injection attacks.
     */
    sanitizeTitle: false
  };

  Lightbox.prototype.option = function(options) {
    $.extend(this.options, options);
  };

  Lightbox.prototype.imageCountLabel = function(currentImageNum, totalImages) {
    return this.options.albumLabel.replace(/%1/g, currentImageNum).replace(/%2/g, totalImages);
  };

  Lightbox.prototype.init = function() {
    var self = this;
    // Both enable and build methods require the body tag to be in the DOM.
    $(document).ready(function() {
      self.enable();
      self.build();
    });
  };

  // Loop through anchors and areamaps looking for either data-lightbox attributes or rel attributes
  // that contain 'lightbox'. When these are clicked, start lightbox.
  Lightbox.prototype.enable = function() {
    var self = this;
    $('body').on('click', 'a[rel^=lightbox], area[rel^=lightbox], a[data-lightbox], area[data-lightbox]', function(event) {
      self.start($(event.currentTarget));
      return false;
    });
  };

  // Build html for the lightbox and the overlay.
  // Attach event handlers to the new DOM elements. click click click
  Lightbox.prototype.build = function() {
    if ($('#lightbox').length > 0) {
        return;
    }

    var self = this;

    // The two root notes generated, #lightboxOverlay and #lightbox are given
    // tabindex attrs so they are focusable. We attach our keyboard event
    // listeners to these two elements, and not the document. Clicking anywhere
    // while Lightbox is opened will keep the focus on or inside one of these
    // two elements.
    //
    // We do this so we can prevent propogation of the Esc keypress when
    // Lightbox is open. This prevents it from intefering with other components
    // on the page below.
    //
    // Github issue: https://github.com/lokesh/lightbox2/issues/663
    $('<div id="lightboxOverlay" tabindex="-1" class="lightboxOverlay"></div><div id="lightbox" tabindex="-1" class="lightbox"><div class="lb-outerContainer"><div class="lb-container"><img class="lb-image" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" alt=""/><div class="lb-nav"><a class="lb-prev" aria-label="Previous image" href="" ></a><a class="lb-next" aria-label="Next image" href="" ></a></div><div class="lb-loader"><a class="lb-cancel"></a></div></div></div><div class="lb-dataContainer"><div class="lb-data"><div class="lb-details"><span class="lb-caption"></span><span class="lb-number"></span></div><div class="lb-closeContainer"><a class="lb-close"></a></div></div></div></div>').appendTo($('body'));

    // Cache jQuery objects
    this.$lightbox       = $('#lightbox');
    this.$overlay        = $('#lightboxOverlay');
    this.$outerContainer = this.$lightbox.find('.lb-outerContainer');
    this.$container      = this.$lightbox.find('.lb-container');
    this.$image          = this.$lightbox.find('.lb-image');
    this.$nav            = this.$lightbox.find('.lb-nav');

    // Store css values for future lookup
    this.containerPadding = {
      top: parseInt(this.$container.css('padding-top'), 10),
      right: parseInt(this.$container.css('padding-right'), 10),
      bottom: parseInt(this.$container.css('padding-bottom'), 10),
      left: parseInt(this.$container.css('padding-left'), 10)
    };

    this.imageBorderWidth = {
      top: parseInt(this.$image.css('border-top-width'), 10),
      right: parseInt(this.$image.css('border-right-width'), 10),
      bottom: parseInt(this.$image.css('border-bottom-width'), 10),
      left: parseInt(this.$image.css('border-left-width'), 10)
    };

    // Attach event handlers to the newly minted DOM elements
    this.$overlay.hide().on('click', function() {
      self.end();
      return false;
    });

    this.$lightbox.hide().on('click', function(event) {
      if ($(event.target).attr('id') === 'lightbox') {
        self.end();
      }
    });

    this.$outerContainer.on('click', function(event) {
      if ($(event.target).attr('id') === 'lightbox') {
        self.end();
      }
      return false;
    });

    this.$lightbox.find('.lb-prev').on('click', function() {
      if (self.currentImageIndex === 0) {
        self.changeImage(self.album.length - 1);
      } else {
        self.changeImage(self.currentImageIndex - 1);
      }
      return false;
    });

    this.$lightbox.find('.lb-next').on('click', function() {
      if (self.currentImageIndex === self.album.length - 1) {
        self.changeImage(0);
      } else {
        self.changeImage(self.currentImageIndex + 1);
      }
      return false;
    });

    /*
      Show context menu for image on right-click

      There is a div containing the navigation that spans the entire image and lives above of it. If
      you right-click, you are right clicking this div and not the image. This prevents users from
      saving the image or using other context menu actions with the image.

      To fix this, when we detect the right mouse button is pressed down, but not yet clicked, we
      set pointer-events to none on the nav div. This is so that the upcoming right-click event on
      the next mouseup will bubble down to the image. Once the right-click/contextmenu event occurs
      we set the pointer events back to auto for the nav div so it can capture hover and left-click
      events as usual.
     */
    this.$nav.on('mousedown', function(event) {
      if (event.which === 3) {
        self.$nav.css('pointer-events', 'none');

        self.$lightbox.one('contextmenu', function() {
          setTimeout(function() {
              this.$nav.css('pointer-events', 'auto');
          }.bind(self), 0);
        });
      }
    });


    this.$lightbox.find('.lb-loader, .lb-close').on('click', function() {
      self.end();
      return false;
    });
  };

  // Show overlay and lightbox. If the image is part of a set, add siblings to album array.
  Lightbox.prototype.start = function($link) {
    var self    = this;
    var $window = $(window);

    $window.on('resize', $.proxy(this.sizeOverlay, this));

    this.sizeOverlay();

    this.album = [];
    var imageNumber = 0;

    function addToAlbum($link) {
      self.album.push({
        alt: $link.attr('data-alt'),
        link: $link.attr('href'),
        title: $link.attr('data-title') || $link.attr('title')
      });
    }

    // Support both data-lightbox attribute and rel attribute implementations
    var dataLightboxValue = $link.attr('data-lightbox');
    var $links;

    if (dataLightboxValue) {
      $links = $($link.prop('tagName') + '[data-lightbox="' + dataLightboxValue + '"]');
      for (var i = 0; i < $links.length; i = ++i) {
        addToAlbum($($links[i]));
        if ($links[i] === $link[0]) {
          imageNumber = i;
        }
      }
    } else {
      if ($link.attr('rel') === 'lightbox') {
        // If image is not part of a set
        addToAlbum($link);
      } else {
        // If image is part of a set
        $links = $($link.prop('tagName') + '[rel="' + $link.attr('rel') + '"]');
        for (var j = 0; j < $links.length; j = ++j) {
          addToAlbum($($links[j]));
          if ($links[j] === $link[0]) {
            imageNumber = j;
          }
        }
      }
    }

    // Position Lightbox
    var top  = $window.scrollTop() + this.options.positionFromTop;
    var left = $window.scrollLeft();
    this.$lightbox.css({
      top: top + 'px',
      left: left + 'px'
    }).fadeIn(this.options.fadeDuration);

    // Disable scrolling of the page while open
    if (this.options.disableScrolling) {
      $('body').addClass('lb-disable-scrolling');
    }

    this.changeImage(imageNumber);
  };

  // Hide most UI elements in preparation for the animated resizing of the lightbox.
  Lightbox.prototype.changeImage = function(imageNumber) {
    var self = this;
    var filename = this.album[imageNumber].link;
    var filetype = filename.split('.').slice(-1)[0];
    var $image = this.$lightbox.find('.lb-image');

    // Disable keyboard nav during transitions
    this.disableKeyboardNav();

    // Show loading state
    this.$overlay.fadeIn(this.options.fadeDuration);
    $('.lb-loader').fadeIn('slow');
    this.$lightbox.find('.lb-image, .lb-nav, .lb-prev, .lb-next, .lb-dataContainer, .lb-numbers, .lb-caption').hide();
    this.$outerContainer.addClass('animating');

    // When image to show is preloaded, we send the width and height to sizeContainer()
    var preloader = new Image();
    preloader.onload = function() {
      var $preloader;
      var imageHeight;
      var imageWidth;
      var maxImageHeight;
      var maxImageWidth;
      var windowHeight;
      var windowWidth;

      $image.attr({
        'alt': self.album[imageNumber].alt,
        'src': filename
      });

      $preloader = $(preloader);

      $image.width(preloader.width);
      $image.height(preloader.height);
      windowWidth = $(window).width();
      windowHeight = $(window).height();

      // Calculate the max image dimensions for the current viewport.
      // Take into account the border around the image and an additional 10px gutter on each side.
      maxImageWidth  = windowWidth - self.containerPadding.left - self.containerPadding.right - self.imageBorderWidth.left - self.imageBorderWidth.right - 20;
      maxImageHeight = windowHeight - self.containerPadding.top - self.containerPadding.bottom - self.imageBorderWidth.top - self.imageBorderWidth.bottom - self.options.positionFromTop - 70;

      /*
      Since many SVGs have small intrinsic dimensions, but they support scaling
      up without quality loss because of their vector format, max out their
      size.
      */
      if (filetype === 'svg') {
        $image.width(maxImageWidth);
        $image.height(maxImageHeight);
      }

      // Fit image inside the viewport.
      if (self.options.fitImagesInViewport) {

        // Check if image size is larger then maxWidth|maxHeight in settings
        if (self.options.maxWidth && self.options.maxWidth < maxImageWidth) {
          maxImageWidth = self.options.maxWidth;
        }
        if (self.options.maxHeight && self.options.maxHeight < maxImageHeight) {
          maxImageHeight = self.options.maxHeight;
        }

      } else {
        maxImageWidth = self.options.maxWidth || preloader.width || maxImageWidth;
        maxImageHeight = self.options.maxHeight || preloader.height || maxImageHeight;
      }

      // Is the current image's width or height is greater than the maxImageWidth or maxImageHeight
      // option than we need to size down while maintaining the aspect ratio.
      if ((preloader.width > maxImageWidth) || (preloader.height > maxImageHeight)) {
        if ((preloader.width / maxImageWidth) > (preloader.height / maxImageHeight)) {
          imageWidth  = maxImageWidth;
          imageHeight = parseInt(preloader.height / (preloader.width / imageWidth), 10);
          $image.width(imageWidth);
          $image.height(imageHeight);
        } else {
          imageHeight = maxImageHeight;
          imageWidth = parseInt(preloader.width / (preloader.height / imageHeight), 10);
          $image.width(imageWidth);
          $image.height(imageHeight);
        }
      }
      self.sizeContainer($image.width(), $image.height());
    };

    // Preload image before showing
    preloader.src = this.album[imageNumber].link;
    this.currentImageIndex = imageNumber;
  };

  // Stretch overlay to fit the viewport
  Lightbox.prototype.sizeOverlay = function() {
    var self = this;
    /*
    We use a setTimeout 0 to pause JS execution and let the rendering catch-up.
    Why do this? If the `disableScrolling` option is set to true, a class is added to the body
    tag that disables scrolling and hides the scrollbar. We want to make sure the scrollbar is
    hidden before we measure the document width, as the presence of the scrollbar will affect the
    number.
    */
    setTimeout(function() {
      self.$overlay
        .width($(document).width())
        .height($(document).height());

    }, 0);
  };

  // Animate the size of the lightbox to fit the image we are showing
  // This method also shows the the image.
  Lightbox.prototype.sizeContainer = function(imageWidth, imageHeight) {
    var self = this;

    var oldWidth  = this.$outerContainer.outerWidth();
    var oldHeight = this.$outerContainer.outerHeight();
    var newWidth  = imageWidth + this.containerPadding.left + this.containerPadding.right + this.imageBorderWidth.left + this.imageBorderWidth.right;
    var newHeight = imageHeight + this.containerPadding.top + this.containerPadding.bottom + this.imageBorderWidth.top + this.imageBorderWidth.bottom;

    function postResize() {
      self.$lightbox.find('.lb-dataContainer').width(newWidth);
      self.$lightbox.find('.lb-prevLink').height(newHeight);
      self.$lightbox.find('.lb-nextLink').height(newHeight);

      // Set focus on one of the two root nodes so keyboard events are captured.
      self.$overlay.focus();

      self.showImage();
    }

    if (oldWidth !== newWidth || oldHeight !== newHeight) {
      this.$outerContainer.animate({
        width: newWidth,
        height: newHeight
      }, this.options.resizeDuration, 'swing', function() {
        postResize();
      });
    } else {
      postResize();
    }
  };

  // Display the image and its details and begin preload neighboring images.
  Lightbox.prototype.showImage = function() {
    this.$lightbox.find('.lb-loader').stop(true).hide();
    this.$lightbox.find('.lb-image').fadeIn(this.options.imageFadeDuration);

    this.updateNav();
    this.updateDetails();
    this.preloadNeighboringImages();
    this.enableKeyboardNav();
  };

  // Display previous and next navigation if appropriate.
  Lightbox.prototype.updateNav = function() {
    // Check to see if the browser supports touch events. If so, we take the conservative approach
    // and assume that mouse hover events are not supported and always show prev/next navigation
    // arrows in image sets.
    var alwaysShowNav = false;
    try {
      document.createEvent('TouchEvent');
      alwaysShowNav = (this.options.alwaysShowNavOnTouchDevices) ? true : false;
    } catch (e) {}

    this.$lightbox.find('.lb-nav').show();

    if (this.album.length > 1) {
      if (this.options.wrapAround) {
        if (alwaysShowNav) {
          this.$lightbox.find('.lb-prev, .lb-next').css('opacity', '1');
        }
        this.$lightbox.find('.lb-prev, .lb-next').show();
      } else {
        if (this.currentImageIndex > 0) {
          this.$lightbox.find('.lb-prev').show();
          if (alwaysShowNav) {
            this.$lightbox.find('.lb-prev').css('opacity', '1');
          }
        }
        if (this.currentImageIndex < this.album.length - 1) {
          this.$lightbox.find('.lb-next').show();
          if (alwaysShowNav) {
            this.$lightbox.find('.lb-next').css('opacity', '1');
          }
        }
      }
    }
  };

  // Display caption, image number, and closing button.
  Lightbox.prototype.updateDetails = function() {
    var self = this;

    // Enable anchor clicks in the injected caption html.
    // Thanks Nate Wright for the fix. @https://github.com/NateWr
    if (typeof this.album[this.currentImageIndex].title !== 'undefined' &&
      this.album[this.currentImageIndex].title !== '') {
      var $caption = this.$lightbox.find('.lb-caption');
      if (this.options.sanitizeTitle) {
        $caption.text(this.album[this.currentImageIndex].title);
      } else {
        $caption.html(this.album[this.currentImageIndex].title);
      }
      $caption.fadeIn('fast');
    }

    if (this.album.length > 1 && this.options.showImageNumberLabel) {
      var labelText = this.imageCountLabel(this.currentImageIndex + 1, this.album.length);
      this.$lightbox.find('.lb-number').text(labelText).fadeIn('fast');
    } else {
      this.$lightbox.find('.lb-number').hide();
    }

    this.$outerContainer.removeClass('animating');

    this.$lightbox.find('.lb-dataContainer').fadeIn(this.options.resizeDuration, function() {
      return self.sizeOverlay();
    });
  };

  // Preload previous and next images in set.
  Lightbox.prototype.preloadNeighboringImages = function() {
    if (this.album.length > this.currentImageIndex + 1) {
      var preloadNext = new Image();
      preloadNext.src = this.album[this.currentImageIndex + 1].link;
    }
    if (this.currentImageIndex > 0) {
      var preloadPrev = new Image();
      preloadPrev.src = this.album[this.currentImageIndex - 1].link;
    }
  };

  Lightbox.prototype.enableKeyboardNav = function() {
    this.$lightbox.on('keyup.keyboard', $.proxy(this.keyboardAction, this));
    this.$overlay.on('keyup.keyboard', $.proxy(this.keyboardAction, this));
  };

  Lightbox.prototype.disableKeyboardNav = function() {
    this.$lightbox.off('.keyboard');
    this.$overlay.off('.keyboard');
  };

  Lightbox.prototype.keyboardAction = function(event) {
    var KEYCODE_ESC        = 27;
    var KEYCODE_LEFTARROW  = 37;
    var KEYCODE_RIGHTARROW = 39;

    var keycode = event.keyCode;
    if (keycode === KEYCODE_ESC) {
      // Prevent bubbling so as to not affect other components on the page.
      event.stopPropagation();
      this.end();
    } else if (keycode === KEYCODE_LEFTARROW) {
      if (this.currentImageIndex !== 0) {
        this.changeImage(this.currentImageIndex - 1);
      } else if (this.options.wrapAround && this.album.length > 1) {
        this.changeImage(this.album.length - 1);
      }
    } else if (keycode === KEYCODE_RIGHTARROW) {
      if (this.currentImageIndex !== this.album.length - 1) {
        this.changeImage(this.currentImageIndex + 1);
      } else if (this.options.wrapAround && this.album.length > 1) {
        this.changeImage(0);
      }
    }
  };

  // Closing time. :-(
  Lightbox.prototype.end = function() {
    this.disableKeyboardNav();
    $(window).off('resize', this.sizeOverlay);
    this.$lightbox.fadeOut(this.options.fadeDuration);
    this.$overlay.fadeOut(this.options.fadeDuration);

    if (this.options.disableScrolling) {
      $('body').removeClass('lb-disable-scrolling');
    }
  };

  return new Lightbox();
}));

/**
 * @Date:   11.08.2020
 * @Email:  info@monster010.de
 * @Filename: effect.blink.js
 * @Last modified time: 11.08.2020
 * @Copyright: Copyright (c) 2020 monster010.de
 */
 (function($) {
	 $.fn.blink = function(option) {
		 var defaults = {
			 delay: 150,
			 class: 'hide',
			 pulses: 5
		 };
		 var options = $.extend(defaults, option);

		 return this.each(function() {
			 var obj = $(this);
			 var count = 0;

			var interval = setInterval(function() {
				if(count == options.pulses) clearInterval(interval);

				 if ($(obj).hasClass(options.class)) {
					 $(obj).removeClass(options.class);
				 }
				 else {
					  $(obj).addClass(options.class);
				 }

				 count++;
			 }, options.delay);
		 });
	 };
 }(jQuery));

(function($) {
	$.fn.shake = function(interval,distance,times) {
		interval = typeof interval == "undefined" ? 100 : interval;
		distance = typeof distance == "undefined" ? 10 : distance;
		times = typeof times == "undefined" ? 3 : times;

		var $target = $(this);

		$target.css('position', 'relative');

		for(var iter = 0; iter < (times + 1); iter++) {
			$target.animate({left: ((iter%2==0 ? distance : distance*-1))}, interval);
		}

		return $target.animate({left: 0}, interval);
	};
})(jQuery);
(function(factory) {
	if(typeof define === 'function' && define.amd) {
		define(['jquery'], factory);
	} else if(typeof module === 'object' && module.exports) {
		module.exports = function(root, jQuery) {
			if(jQuery === undefined) {
				if(typeof window !== 'undefined') {
					jQuery = require('jquery');
				} else {
					jQuery = require('jquery')(root);
				}
			}
			factory(jQuery);
			return jQuery;
		};
	} else {
		factory(jQuery);
	}
}(function($) {
	'use strict';

	$.fn.animateCSS = function(animation) {
		var options = {};

		if(typeof arguments[1] === 'object') {
			options = arguments[1];
		} else if(typeof arguments[1] === 'function') {
			options.complete = arguments[1];
		} else if(typeof arguments[1] === 'number') {
			options.duration = arguments[1];
			if(typeof arguments[2] === 'function') options.complete = arguments[2];
		}

		options = $.extend(true, {
			animation: animation,
			complete: function() {},
			delay: 0,
			duration: 1000
		}, options);

		$(this).each(function() {
			var el = this;

			if(options.duration) {
				$(el).css({
					'-moz-animation-duration': options.duration + 'ms',
					'-o-animation-duration': options.duration + 'ms',
					'-webkit-animation-duration': options.duration + 'ms',
					'animation-duration': options.duration + 'ms'
				});
			}

			if(options.delay <= 0) {
				animateCSS(el, options).then(r => options.complete.call(el));
			} else {
				setTimeout(function() {
					animateCSS(el, options).then(r => options.complete.call(el));
				}, options.delay);
			}
		});

		return this;
	};
}));

const animateCSS = (element, options) => {
	if(typeof options === 'string') {
		let animation = options;
		options = {};

		options.animation = animation;
	}

	return new Promise((resolve, reject) => {
		var animationEnd = 'animationend mozAnimationEnd MSAnimationEnd oanimationend webkitAnimationEnd';

		const animationName = `${animate_prefix}${options.animation}`;
		const node = $(element);

		node.addClass(`${animate_prefix}animated ${animationName}`);

		node.on(animationEnd, () => {
			node.off(animationEnd);
			node.removeClass(`${animate_prefix}animated  ${animationName}`);

			resolve('Animation ended');
		});
	});
};

(function($) {
	$.fn.getFormData = function() {
		var data = {};
		var dataArray = $(this).serializeArray();

		for(var i=0; i < dataArray.length; i++) {
			data[dataArray[i].name] = dataArray[i].value;
		}

		return data;
	};
})(jQuery);
(function($){
	$.fn.toScroll = function() {
		var $this = $(this);
		$('body').scrollTo($this, 800, {offset: -150});
	};

	$.fn.genAlert = function(type, message) {
		$(this).html('<div class="alert alert-' + type + '" role="alert">' + message + '</div>');
		return $(this);
	};

	$.fn.genAlertTitle = function(type, title, message) {
		$(this).html('<div class="alert alert-' + type + '" role="alert"><h4>' + title + '</h4>' + message + '</div>');
		return $(this);
	};

	$.extend({
		notify: function(type, message) {
			if(typeof type === 'object') {$.notify(type.type, type.message); return;}

			toastr.options = {
				"closeButton": false,
				"progressBar": true,
				"onclick": null,
				"newestOnTop": true,
				"preventDuplicates": false,
				"positionClass": "toast-top-right",
				"showDuration": "5000",
				"hideDuration": "10000",
				"timeOut": "7000",
				"extendedTimeOut": "1000",
				"showEasing": "swing",
				"hideEasing": "linear",
				"showMethod": "fadeIn",
				"hideMethod": "fadeOut"
			};

			if(type === "success") {
				toastr.success(message);
			} else if(type === "warning") {
				toastr.warning(message);
			} else if(type === "error") {
				toastr.error(message);
			} else {
				toastr.info(message);
			}
		},
		notify_title: function(type, title, message) {
			if(typeof type === 'object') {$.notify_title(type.type, type.title, type.message); return;}

			toastr.options = {
				"closeButton": false,
				"progressBar": true,
				"onclick": null,
				"newestOnTop": true,
				"preventDuplicates": false,
				"positionClass": "toast-top-right",
				"showDuration": "5000",
				"hideDuration": "10000",
				"timeOut": "7000",
				"extendedTimeOut": "1000",
				"showEasing": "swing",
				"hideEasing": "linear",
				"showMethod": "fadeIn",
				"hideMethod": "fadeOut"
			};

			if(type === "success") {
				toastr.success(message, title);
			} else if(type === "warning") {
				toastr.warning(message, title);
			} else if(type === "error") {
				toastr.error(message, title);
			} else {
				toastr.info(message, title);
			}
		}
	});

	$('[data-toggle="password"]').click(function() {
		$(this).toggleClass('fa-eye fa-eye-slash');

		var $input = $($(this).data('target'));

		if($input.attr("type") == 'password') {
			$input.attr("type", "text");
		} else {
			$input.attr("type", "password");
		}
	});
})(jQuery);