
//     Underscore.js 1.5.2
//     http://underscorejs.org
//     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
//     Underscore may be freely distributed under the MIT license.

(function() {

    // Baseline setup
    // --------------

    // Establish the root object, `window` in the browser, or `exports` on the server.
    var root = this;

    // Save the previous value of the `_` variable.
    var previousUnderscore = root._;

    // Establish the object that gets returned to break out of a loop iteration.
    var breaker = {};

    // Save bytes in the minified (but not gzipped) version:
    var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;

    // Create quick reference variables for speed access to core prototypes.
    var
        push             = ArrayProto.push,
        slice            = ArrayProto.slice,
        concat           = ArrayProto.concat,
        toString         = ObjProto.toString,
        hasOwnProperty   = ObjProto.hasOwnProperty;

    // All **ECMAScript 5** native function implementations that we hope to use
    // are declared here.
    var
        nativeForEach      = ArrayProto.forEach,
        nativeMap          = ArrayProto.map,
        nativeReduce       = ArrayProto.reduce,
        nativeReduceRight  = ArrayProto.reduceRight,
        nativeFilter       = ArrayProto.filter,
        nativeEvery        = ArrayProto.every,
        nativeSome         = ArrayProto.some,
        nativeIndexOf      = ArrayProto.indexOf,
        nativeLastIndexOf  = ArrayProto.lastIndexOf,
        nativeIsArray      = Array.isArray,
        nativeKeys         = Object.keys,
        nativeBind         = FuncProto.bind;

    // Create a safe reference to the Underscore object for use below.
    var _ = function(obj) {
        if (obj instanceof _) return obj;
        if (!(this instanceof _)) return new _(obj);
        this._wrapped = obj;
    };

    // Export the Underscore object for **Node.js**, with
    // backwards-compatibility for the old `require()` API. If we're in
    // the browser, add `_` as a global object via a string identifier,
    // for Closure Compiler "advanced" mode.
    if (typeof exports !== 'undefined') {
        if (typeof module !== 'undefined' && module.exports) {
            exports = module.exports = _;
        }
        exports._ = _;
    } else {
        root._ = _;
    }

    // Current version.
    _.VERSION = '1.5.2';

    // Collection Functions
    // --------------------

    // The cornerstone, an `each` implementation, aka `forEach`.
    // Handles objects with the built-in `forEach`, arrays, and raw objects.
    // Delegates to **ECMAScript 5**'s native `forEach` if available.
    var each = _.each = _.forEach = function(obj, iterator, context) {
        if (obj == null) return;
        if (nativeForEach && obj.forEach === nativeForEach) {
            obj.forEach(iterator, context);
        } else if (obj.length === +obj.length) {
            for (var i = 0, length = obj.length; i < length; i++) {
                if (iterator.call(context, obj[i], i, obj) === breaker) return;
            }
        } else {
            var keys = _.keys(obj);
            for (var i = 0, length = keys.length; i < length; i++) {
                if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
            }
        }
    };

    // Return the results of applying the iterator to each element.
    // Delegates to **ECMAScript 5**'s native `map` if available.
    _.map = _.collect = function(obj, iterator, context) {
        var results = [];
        if (obj == null) return results;
        if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
        each(obj, function(value, index, list) {
            results.push(iterator.call(context, value, index, list));
        });
        return results;
    };

    var reduceError = 'Reduce of empty array with no initial value';

    // **Reduce** builds up a single result from a list of values, aka `inject`,
    // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
    _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
        var initial = arguments.length > 2;
        if (obj == null) obj = [];
        if (nativeReduce && obj.reduce === nativeReduce) {
            if (context) iterator = _.bind(iterator, context);
            return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
        }
        each(obj, function(value, index, list) {
            if (!initial) {
                memo = value;
                initial = true;
            } else {
                memo = iterator.call(context, memo, value, index, list);
            }
        });
        if (!initial) throw new TypeError(reduceError);
        return memo;
    };

    // The right-associative version of reduce, also known as `foldr`.
    // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
    _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
        var initial = arguments.length > 2;
        if (obj == null) obj = [];
        if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
            if (context) iterator = _.bind(iterator, context);
            return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
        }
        var length = obj.length;
        if (length !== +length) {
            var keys = _.keys(obj);
            length = keys.length;
        }
        each(obj, function(value, index, list) {
            index = keys ? keys[--length] : --length;
            if (!initial) {
                memo = obj[index];
                initial = true;
            } else {
                memo = iterator.call(context, memo, obj[index], index, list);
            }
        });
        if (!initial) throw new TypeError(reduceError);
        return memo;
    };

    // Return the first value which passes a truth test. Aliased as `detect`.
    _.find = _.detect = function(obj, iterator, context) {
        var result;
        any(obj, function(value, index, list) {
            if (iterator.call(context, value, index, list)) {
                result = value;
                return true;
            }
        });
        return result;
    };

    // Return all the elements that pass a truth test.
    // Delegates to **ECMAScript 5**'s native `filter` if available.
    // Aliased as `select`.
    _.filter = _.select = function(obj, iterator, context) {
        var results = [];
        if (obj == null) return results;
        if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
        each(obj, function(value, index, list) {
            if (iterator.call(context, value, index, list)) results.push(value);
        });
        return results;
    };

    // Return all the elements for which a truth test fails.
    _.reject = function(obj, iterator, context) {
        return _.filter(obj, function(value, index, list) {
            return !iterator.call(context, value, index, list);
        }, context);
    };

    // Determine whether all of the elements match a truth test.
    // Delegates to **ECMAScript 5**'s native `every` if available.
    // Aliased as `all`.
    _.every = _.all = function(obj, iterator, context) {
        iterator || (iterator = _.identity);
        var result = true;
        if (obj == null) return result;
        if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
        each(obj, function(value, index, list) {
            if (!(result = result && iterator.call(context, value, index, list))) return breaker;
        });
        return !!result;
    };

    // Determine if at least one element in the object matches a truth test.
    // Delegates to **ECMAScript 5**'s native `some` if available.
    // Aliased as `any`.
    var any = _.some = _.any = function(obj, iterator, context) {
        iterator || (iterator = _.identity);
        var result = false;
        if (obj == null) return result;
        if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
        each(obj, function(value, index, list) {
            if (result || (result = iterator.call(context, value, index, list))) return breaker;
        });
        return !!result;
    };

    // Determine if the array or object contains a given value (using `===`).
    // Aliased as `include`.
    _.contains = _.include = function(obj, target) {
        if (obj == null) return false;
        if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
        return any(obj, function(value) {
            return value === target;
        });
    };

    // Invoke a method (with arguments) on every item in a collection.
    _.invoke = function(obj, method) {
        var args = slice.call(arguments, 2);
        var isFunc = _.isFunction(method);
        return _.map(obj, function(value) {
            return (isFunc ? method : value[method]).apply(value, args);
        });
    };

    // Convenience version of a common use case of `map`: fetching a property.
    _.pluck = function(obj, key) {
        return _.map(obj, function(value){ return value[key]; });
    };

    // Convenience version of a common use case of `filter`: selecting only objects
    // containing specific `key:value` pairs.
    _.where = function(obj, attrs, first) {
        if (_.isEmpty(attrs)) return first ? void 0 : [];
        return _[first ? 'find' : 'filter'](obj, function(value) {
            for (var key in attrs) {
                if (attrs[key] !== value[key]) return false;
            }
            return true;
        });
    };

    // Convenience version of a common use case of `find`: getting the first object
    // containing specific `key:value` pairs.
    _.findWhere = function(obj, attrs) {
        return _.where(obj, attrs, true);
    };

    // Return the maximum element or (element-based computation).
    // Can't optimize arrays of integers longer than 65,535 elements.
    // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
    _.max = function(obj, iterator, context) {
        if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
            return Math.max.apply(Math, obj);
        }
        if (!iterator && _.isEmpty(obj)) return -Infinity;
        var result = {computed : -Infinity, value: -Infinity};
        each(obj, function(value, index, list) {
            var computed = iterator ? iterator.call(context, value, index, list) : value;
            computed > result.computed && (result = {value : value, computed : computed});
        });
        return result.value;
    };

    // Return the minimum element (or element-based computation).
    _.min = function(obj, iterator, context) {
        if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
            return Math.min.apply(Math, obj);
        }
        if (!iterator && _.isEmpty(obj)) return Infinity;
        var result = {computed : Infinity, value: Infinity};
        each(obj, function(value, index, list) {
            var computed = iterator ? iterator.call(context, value, index, list) : value;
            computed < result.computed && (result = {value : value, computed : computed});
        });
        return result.value;
    };

    // Shuffle an array, using the modern version of the
    // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisherâ€“Yates_shuffle).
    _.shuffle = function(obj) {
        var rand;
        var index = 0;
        var shuffled = [];
        each(obj, function(value) {
            rand = _.random(index++);
            shuffled[index - 1] = shuffled[rand];
            shuffled[rand] = value;
        });
        return shuffled;
    };

    // Sample **n** random values from an array.
    // If **n** is not specified, returns a single random element from the array.
    // The internal `guard` argument allows it to work with `map`.
    _.sample = function(obj, n, guard) {
        if (arguments.length < 2 || guard) {
            return obj[_.random(obj.length - 1)];
        }
        return _.shuffle(obj).slice(0, Math.max(0, n));
    };

    // An internal function to generate lookup iterators.
    var lookupIterator = function(value) {
        return _.isFunction(value) ? value : function(obj){ return obj[value]; };
    };

    // Sort the object's values by a criterion produced by an iterator.
    _.sortBy = function(obj, value, context) {
        var iterator = lookupIterator(value);
        return _.pluck(_.map(obj, function(value, index, list) {
            return {
                value: value,
                index: index,
                criteria: iterator.call(context, value, index, list)
            };
        }).sort(function(left, right) {
                var a = left.criteria;
                var b = right.criteria;
                if (a !== b) {
                    if (a > b || a === void 0) return 1;
                    if (a < b || b === void 0) return -1;
                }
                return left.index - right.index;
            }), 'value');
    };

    // An internal function used for aggregate "group by" operations.
    var group = function(behavior) {
        return function(obj, value, context) {
            var result = {};
            var iterator = value == null ? _.identity : lookupIterator(value);
            each(obj, function(value, index) {
                var key = iterator.call(context, value, index, obj);
                behavior(result, key, value);
            });
            return result;
        };
    };

    // Groups the object's values by a criterion. Pass either a string attribute
    // to group by, or a function that returns the criterion.
    _.groupBy = group(function(result, key, value) {
        (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
    });

    // Indexes the object's values by a criterion, similar to `groupBy`, but for
    // when you know that your index values will be unique.
    _.indexBy = group(function(result, key, value) {
        result[key] = value;
    });

    // Counts instances of an object that group by a certain criterion. Pass
    // either a string attribute to count by, or a function that returns the
    // criterion.
    _.countBy = group(function(result, key) {
        _.has(result, key) ? result[key]++ : result[key] = 1;
    });

    // Use a comparator function to figure out the smallest index at which
    // an object should be inserted so as to maintain order. Uses binary search.
    _.sortedIndex = function(array, obj, iterator, context) {
        iterator = iterator == null ? _.identity : lookupIterator(iterator);
        var value = iterator.call(context, obj);
        var low = 0, high = array.length;
        while (low < high) {
            var mid = (low + high) >>> 1;
            iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
        }
        return low;
    };

    // Safely create a real, live array from anything iterable.
    _.toArray = function(obj) {
        if (!obj) return [];
        if (_.isArray(obj)) return slice.call(obj);
        if (obj.length === +obj.length) return _.map(obj, _.identity);
        return _.values(obj);
    };

    // Return the number of elements in an object.
    _.size = function(obj) {
        if (obj == null) return 0;
        return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
    };

    // Array Functions
    // ---------------

    // Get the first element of an array. Passing **n** will return the first N
    // values in the array. Aliased as `head` and `take`. The **guard** check
    // allows it to work with `_.map`.
    _.first = _.head = _.take = function(array, n, guard) {
        if (array == null) return void 0;
        return (n == null) || guard ? array[0] : slice.call(array, 0, n);
    };

    // Returns everything but the last entry of the array. Especially useful on
    // the arguments object. Passing **n** will return all the values in
    // the array, excluding the last N. The **guard** check allows it to work with
    // `_.map`.
    _.initial = function(array, n, guard) {
        return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
    };

    // Get the last element of an array. Passing **n** will return the last N
    // values in the array. The **guard** check allows it to work with `_.map`.
    _.last = function(array, n, guard) {
        if (array == null) return void 0;
        if ((n == null) || guard) {
            return array[array.length - 1];
        } else {
            return slice.call(array, Math.max(array.length - n, 0));
        }
    };

    // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
    // Especially useful on the arguments object. Passing an **n** will return
    // the rest N values in the array. The **guard**
    // check allows it to work with `_.map`.
    _.rest = _.tail = _.drop = function(array, n, guard) {
        return slice.call(array, (n == null) || guard ? 1 : n);
    };

    // Trim out all falsy values from an array.
    _.compact = function(array) {
        return _.filter(array, _.identity);
    };

    // Internal implementation of a recursive `flatten` function.
    var flatten = function(input, shallow, output) {
        if (shallow && _.every(input, _.isArray)) {
            return concat.apply(output, input);
        }
        each(input, function(value) {
            if (_.isArray(value) || _.isArguments(value)) {
                shallow ? push.apply(output, value) : flatten(value, shallow, output);
            } else {
                output.push(value);
            }
        });
        return output;
    };

    // Flatten out an array, either recursively (by default), or just one level.
    _.flatten = function(array, shallow) {
        return flatten(array, shallow, []);
    };

    // Return a version of the array that does not contain the specified value(s).
    _.without = function(array) {
        return _.difference(array, slice.call(arguments, 1));
    };

    // Produce a duplicate-free version of the array. If the array has already
    // been sorted, you have the option of using a faster algorithm.
    // Aliased as `unique`.
    _.uniq = _.unique = function(array, isSorted, iterator, context) {
        if (_.isFunction(isSorted)) {
            context = iterator;
            iterator = isSorted;
            isSorted = false;
        }
        var initial = iterator ? _.map(array, iterator, context) : array;
        var results = [];
        var seen = [];
        each(initial, function(value, index) {
            if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
                seen.push(value);
                results.push(array[index]);
            }
        });
        return results;
    };

    // Produce an array that contains the union: each distinct element from all of
    // the passed-in arrays.
    _.union = function() {
        return _.uniq(_.flatten(arguments, true));
    };

    // Produce an array that contains every item shared between all the
    // passed-in arrays.
    _.intersection = function(array) {
        var rest = slice.call(arguments, 1);
        return _.filter(_.uniq(array), function(item) {
            return _.every(rest, function(other) {
                return _.indexOf(other, item) >= 0;
            });
        });
    };

    // Take the difference between one array and a number of other arrays.
    // Only the elements present in just the first array will remain.
    _.difference = function(array) {
        var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
        return _.filter(array, function(value){ return !_.contains(rest, value); });
    };

    // Zip together multiple lists into a single array -- elements that share
    // an index go together.
    _.zip = function() {
        var length = _.max(_.pluck(arguments, "length").concat(0));
        var results = new Array(length);
        for (var i = 0; i < length; i++) {
            results[i] = _.pluck(arguments, '' + i);
        }
        return results;
    };

    // Converts lists into objects. Pass either a single array of `[key, value]`
    // pairs, or two parallel arrays of the same length -- one of keys, and one of
    // the corresponding values.
    _.object = function(list, values) {
        if (list == null) return {};
        var result = {};
        for (var i = 0, length = list.length; i < length; i++) {
            if (values) {
                result[list[i]] = values[i];
            } else {
                result[list[i][0]] = list[i][1];
            }
        }
        return result;
    };

    // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
    // we need this function. Return the position of the first occurrence of an
    // item in an array, or -1 if the item is not included in the array.
    // Delegates to **ECMAScript 5**'s native `indexOf` if available.
    // If the array is large and already in sort order, pass `true`
    // for **isSorted** to use binary search.
    _.indexOf = function(array, item, isSorted) {
        if (array == null) return -1;
        var i = 0, length = array.length;
        if (isSorted) {
            if (typeof isSorted == 'number') {
                i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
            } else {
                i = _.sortedIndex(array, item);
                return array[i] === item ? i : -1;
            }
        }
        if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
        for (; i < length; i++) if (array[i] === item) return i;
        return -1;
    };

    // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
    _.lastIndexOf = function(array, item, from) {
        if (array == null) return -1;
        var hasIndex = from != null;
        if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
            return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
        }
        var i = (hasIndex ? from : array.length);
        while (i--) if (array[i] === item) return i;
        return -1;
    };

    // Generate an integer Array containing an arithmetic progression. A port of
    // the native Python `range()` function. See
    // [the Python documentation](http://docs.python.org/library/functions.html#range).
    _.range = function(start, stop, step) {
        if (arguments.length <= 1) {
            stop = start || 0;
            start = 0;
        }
        step = arguments[2] || 1;

        var length = Math.max(Math.ceil((stop - start) / step), 0);
        var idx = 0;
        var range = new Array(length);

        while(idx < length) {
            range[idx++] = start;
            start += step;
        }

        return range;
    };

    // Function (ahem) Functions
    // ------------------

    // Reusable constructor function for prototype setting.
    var ctor = function(){};

    // Create a function bound to a given object (assigning `this`, and arguments,
    // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
    // available.
    _.bind = function(func, context) {
        var args, bound;
        if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
        if (!_.isFunction(func)) throw new TypeError;
        args = slice.call(arguments, 2);
        return bound = function() {
            if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
            ctor.prototype = func.prototype;
            var self = new ctor;
            ctor.prototype = null;
            var result = func.apply(self, args.concat(slice.call(arguments)));
            if (Object(result) === result) return result;
            return self;
        };
    };

    // Partially apply a function by creating a version that has had some of its
    // arguments pre-filled, without changing its dynamic `this` context.
    _.partial = function(func) {
        var args = slice.call(arguments, 1);
        return function() {
            return func.apply(this, args.concat(slice.call(arguments)));
        };
    };

    // Bind all of an object's methods to that object. Useful for ensuring that
    // all callbacks defined on an object belong to it.
    _.bindAll = function(obj) {
        var funcs = slice.call(arguments, 1);
        if (funcs.length === 0) throw new Error("bindAll must be passed function names");
        each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
        return obj;
    };

    // Memoize an expensive function by storing its results.
    _.memoize = function(func, hasher) {
        var memo = {};
        hasher || (hasher = _.identity);
        return function() {
            var key = hasher.apply(this, arguments);
            return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
        };
    };

    // Delays a function for the given number of milliseconds, and then calls
    // it with the arguments supplied.
    _.delay = function(func, wait) {
        var args = slice.call(arguments, 2);
        return setTimeout(function(){ return func.apply(null, args); }, wait);
    };

    // Defers a function, scheduling it to run after the current call stack has
    // cleared.
    _.defer = function(func) {
        return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
    };

    // Returns a function, that, when invoked, will only be triggered at most once
    // during a given window of time. Normally, the throttled function will run
    // as much as it can, without ever going more than once per `wait` duration;
    // but if you'd like to disable the execution on the leading edge, pass
    // `{leading: false}`. To disable execution on the trailing edge, ditto.
    _.throttle = function(func, wait, options) {
        var context, args, result;
        var timeout = null;
        var previous = 0;
        options || (options = {});
        var later = function() {
            previous = options.leading === false ? 0 : new Date;
            timeout = null;
            result = func.apply(context, args);
        };
        return function() {
            var now = new Date;
            if (!previous && options.leading === false) previous = now;
            var remaining = wait - (now - previous);
            context = this;
            args = arguments;
            if (remaining <= 0) {
                clearTimeout(timeout);
                timeout = null;
                previous = now;
                result = func.apply(context, args);
            } else if (!timeout && options.trailing !== false) {
                timeout = setTimeout(later, remaining);
            }
            return result;
        };
    };

    // Returns a function, that, as long as it continues to be invoked, will not
    // be triggered. The function will be called after it stops being called for
    // N milliseconds. If `immediate` is passed, trigger the function on the
    // leading edge, instead of the trailing.
    _.debounce = function(func, wait, immediate) {
        var timeout, args, context, timestamp, result;
        return function() {
            context = this;
            args = arguments;
            timestamp = new Date();
            var later = function() {
                var last = (new Date()) - timestamp;
                if (last < wait) {
                    timeout = setTimeout(later, wait - last);
                } else {
                    timeout = null;
                    if (!immediate) result = func.apply(context, args);
                }
            };
            var callNow = immediate && !timeout;
            if (!timeout) {
                timeout = setTimeout(later, wait);
            }
            if (callNow) result = func.apply(context, args);
            return result;
        };
    };

    // Returns a function that will be executed at most one time, no matter how
    // often you call it. Useful for lazy initialization.
    _.once = function(func) {
        var ran = false, memo;
        return function() {
            if (ran) return memo;
            ran = true;
            memo = func.apply(this, arguments);
            func = null;
            return memo;
        };
    };

    // Returns the first function passed as an argument to the second,
    // allowing you to adjust arguments, run code before and after, and
    // conditionally execute the original function.
    _.wrap = function(func, wrapper) {
        return function() {
            var args = [func];
            push.apply(args, arguments);
            return wrapper.apply(this, args);
        };
    };

    // Returns a function that is the composition of a list of functions, each
    // consuming the return value of the function that follows.
    _.compose = function() {
        var funcs = arguments;
        return function() {
            var args = arguments;
            for (var i = funcs.length - 1; i >= 0; i--) {
                args = [funcs[i].apply(this, args)];
            }
            return args[0];
        };
    };

    // Returns a function that will only be executed after being called N times.
    _.after = function(times, func) {
        return function() {
            if (--times < 1) {
                return func.apply(this, arguments);
            }
        };
    };

    // Object Functions
    // ----------------

    // Retrieve the names of an object's properties.
    // Delegates to **ECMAScript 5**'s native `Object.keys`
    _.keys = nativeKeys || function(obj) {
        if (obj !== Object(obj)) throw new TypeError('Invalid object');
        var keys = [];
        for (var key in obj) if (_.has(obj, key)) keys.push(key);
        return keys;
    };

    // Retrieve the values of an object's properties.
    _.values = function(obj) {
        var keys = _.keys(obj);
        var length = keys.length;
        var values = new Array(length);
        for (var i = 0; i < length; i++) {
            values[i] = obj[keys[i]];
        }
        return values;
    };

    // Convert an object into a list of `[key, value]` pairs.
    _.pairs = function(obj) {
        var keys = _.keys(obj);
        var length = keys.length;
        var pairs = new Array(length);
        for (var i = 0; i < length; i++) {
            pairs[i] = [keys[i], obj[keys[i]]];
        }
        return pairs;
    };

    // Invert the keys and values of an object. The values must be serializable.
    _.invert = function(obj) {
        var result = {};
        var keys = _.keys(obj);
        for (var i = 0, length = keys.length; i < length; i++) {
            result[obj[keys[i]]] = keys[i];
        }
        return result;
    };

    // Return a sorted list of the function names available on the object.
    // Aliased as `methods`
    _.functions = _.methods = function(obj) {
        var names = [];
        for (var key in obj) {
            if (_.isFunction(obj[key])) names.push(key);
        }
        return names.sort();
    };

    // Extend a given object with all the properties in passed-in object(s).
    _.extend = function(obj) {
        each(slice.call(arguments, 1), function(source) {
            if (source) {
                for (var prop in source) {
                    obj[prop] = source[prop];
                }
            }
        });
        return obj;
    };

    // Return a copy of the object only containing the whitelisted properties.
    _.pick = function(obj) {
        var copy = {};
        var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
        each(keys, function(key) {
            if (key in obj) copy[key] = obj[key];
        });
        return copy;
    };

    // Return a copy of the object without the blacklisted properties.
    _.omit = function(obj) {
        var copy = {};
        var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
        for (var key in obj) {
            if (!_.contains(keys, key)) copy[key] = obj[key];
        }
        return copy;
    };

    // Fill in a given object with default properties.
    _.defaults = function(obj) {
        each(slice.call(arguments, 1), function(source) {
            if (source) {
                for (var prop in source) {
                    if (obj[prop] === void 0) obj[prop] = source[prop];
                }
            }
        });
        return obj;
    };

    // Create a (shallow-cloned) duplicate of an object.
    _.clone = function(obj) {
        if (!_.isObject(obj)) return obj;
        return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
    };

    // Invokes interceptor with the obj, and then returns obj.
    // The primary purpose of this method is to "tap into" a method chain, in
    // order to perform operations on intermediate results within the chain.
    _.tap = function(obj, interceptor) {
        interceptor(obj);
        return obj;
    };

    // Internal recursive comparison function for `isEqual`.
    var eq = function(a, b, aStack, bStack) {
        // Identical objects are equal. `0 === -0`, but they aren't identical.
        // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
        if (a === b) return a !== 0 || 1 / a == 1 / b;
        // A strict comparison is necessary because `null == undefined`.
        if (a == null || b == null) return a === b;
        // Unwrap any wrapped objects.
        if (a instanceof _) a = a._wrapped;
        if (b instanceof _) b = b._wrapped;
        // Compare `[[Class]]` names.
        var className = toString.call(a);
        if (className != toString.call(b)) return false;
        switch (className) {
            // Strings, numbers, dates, and booleans are compared by value.
            case '[object String]':
                // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
                // equivalent to `new String("5")`.
                return a == String(b);
            case '[object Number]':
                // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
                // other numeric values.
                return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
            case '[object Date]':
            case '[object Boolean]':
                // Coerce dates and booleans to numeric primitive values. Dates are compared by their
                // millisecond representations. Note that invalid dates with millisecond representations
                // of `NaN` are not equivalent.
                return +a == +b;
            // RegExps are compared by their source patterns and flags.
            case '[object RegExp]':
                return a.source == b.source &&
                    a.global == b.global &&
                    a.multiline == b.multiline &&
                    a.ignoreCase == b.ignoreCase;
        }
        if (typeof a != 'object' || typeof b != 'object') return false;
        // Assume equality for cyclic structures. The algorithm for detecting cyclic
        // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
        var length = aStack.length;
        while (length--) {
            // Linear search. Performance is inversely proportional to the number of
            // unique nested structures.
            if (aStack[length] == a) return bStack[length] == b;
        }
        // Objects with different constructors are not equivalent, but `Object`s
        // from different frames are.
        var aCtor = a.constructor, bCtor = b.constructor;
        if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
            _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
            return false;
        }
        // Add the first object to the stack of traversed objects.
        aStack.push(a);
        bStack.push(b);
        var size = 0, result = true;
        // Recursively compare objects and arrays.
        if (className == '[object Array]') {
            // Compare array lengths to determine if a deep comparison is necessary.
            size = a.length;
            result = size == b.length;
            if (result) {
                // Deep compare the contents, ignoring non-numeric properties.
                while (size--) {
                    if (!(result = eq(a[size], b[size], aStack, bStack))) break;
                }
            }
        } else {
            // Deep compare objects.
            for (var key in a) {
                if (_.has(a, key)) {
                    // Count the expected number of properties.
                    size++;
                    // Deep compare each member.
                    if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
                }
            }
            // Ensure that both objects contain the same number of properties.
            if (result) {
                for (key in b) {
                    if (_.has(b, key) && !(size--)) break;
                }
                result = !size;
            }
        }
        // Remove the first object from the stack of traversed objects.
        aStack.pop();
        bStack.pop();
        return result;
    };

    // Perform a deep comparison to check if two objects are equal.
    _.isEqual = function(a, b) {
        return eq(a, b, [], []);
    };

    // Is a given array, string, or object empty?
    // An "empty" object has no enumerable own-properties.
    _.isEmpty = function(obj) {
        if (obj == null) return true;
        if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
        for (var key in obj) if (_.has(obj, key)) return false;
        return true;
    };

    // Is a given value a DOM element?
    _.isElement = function(obj) {
        return !!(obj && obj.nodeType === 1);
    };

    // Is a given value an array?
    // Delegates to ECMA5's native Array.isArray
    _.isArray = nativeIsArray || function(obj) {
        return toString.call(obj) == '[object Array]';
    };

    // Is a given variable an object?
    _.isObject = function(obj) {
        return obj === Object(obj);
    };

    // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
    each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
        _['is' + name] = function(obj) {
            return toString.call(obj) == '[object ' + name + ']';
        };
    });

    // Define a fallback version of the method in browsers (ahem, IE), where
    // there isn't any inspectable "Arguments" type.
    if (!_.isArguments(arguments)) {
        _.isArguments = function(obj) {
            return !!(obj && _.has(obj, 'callee'));
        };
    }

    // Optimize `isFunction` if appropriate.
    if (typeof (/./) !== 'function') {
        _.isFunction = function(obj) {
            return typeof obj === 'function';
        };
    }

    // Is a given object a finite number?
    _.isFinite = function(obj) {
        return isFinite(obj) && !isNaN(parseFloat(obj));
    };

    // Is the given value `NaN`? (NaN is the only number which does not equal itself).
    _.isNaN = function(obj) {
        return _.isNumber(obj) && obj != +obj;
    };

    // Is a given value a boolean?
    _.isBoolean = function(obj) {
        return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
    };

    // Is a given value equal to null?
    _.isNull = function(obj) {
        return obj === null;
    };

    // Is a given variable undefined?
    _.isUndefined = function(obj) {
        return obj === void 0;
    };

    // Shortcut function for checking if an object has a given property directly
    // on itself (in other words, not on a prototype).
    _.has = function(obj, key) {
        return hasOwnProperty.call(obj, key);
    };

    // Utility Functions
    // -----------------

    // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
    // previous owner. Returns a reference to the Underscore object.
    _.noConflict = function() {
        root._ = previousUnderscore;
        return this;
    };

    // Keep the identity function around for default iterators.
    _.identity = function(value) {
        return value;
    };

    // Run a function **n** times.
    _.times = function(n, iterator, context) {
        var accum = Array(Math.max(0, n));
        for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
        return accum;
    };

    // Return a random integer between min and max (inclusive).
    _.random = function(min, max) {
        if (max == null) {
            max = min;
            min = 0;
        }
        return min + Math.floor(Math.random() * (max - min + 1));
    };

    // List of HTML entities for escaping.
    var entityMap = {
        escape: {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            "'": '&#x27;'
        }
    };
    entityMap.unescape = _.invert(entityMap.escape);

    // Regexes containing the keys and values listed immediately above.
    var entityRegexes = {
        escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
        unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
    };

    // Functions for escaping and unescaping strings to/from HTML interpolation.
    _.each(['escape', 'unescape'], function(method) {
        _[method] = function(string) {
            if (string == null) return '';
            return ('' + string).replace(entityRegexes[method], function(match) {
                return entityMap[method][match];
            });
        };
    });

    // If the value of the named `property` is a function then invoke it with the
    // `object` as context; otherwise, return it.
    _.result = function(object, property) {
        if (object == null) return void 0;
        var value = object[property];
        return _.isFunction(value) ? value.call(object) : value;
    };

    // Add your own custom functions to the Underscore object.
    _.mixin = function(obj) {
        each(_.functions(obj), function(name) {
            var func = _[name] = obj[name];
            _.prototype[name] = function() {
                var args = [this._wrapped];
                push.apply(args, arguments);
                return result.call(this, func.apply(_, args));
            };
        });
    };

    // Generate a unique integer id (unique within the entire client session).
    // Useful for temporary DOM ids.
    var idCounter = 0;
    _.uniqueId = function(prefix) {
        var id = ++idCounter + '';
        return prefix ? prefix + id : id;
    };

    // By default, Underscore uses ERB-style template delimiters, change the
    // following template settings to use alternative delimiters.
    _.templateSettings = {
        evaluate    : /<%([\s\S]+?)%>/g,
        interpolate : /<%=([\s\S]+?)%>/g,
        escape      : /<%-([\s\S]+?)%>/g
    };

    // When customizing `templateSettings`, if you don't want to define an
    // interpolation, evaluation or escaping regex, we need one that is
    // guaranteed not to match.
    var noMatch = /(.)^/;

    // Certain characters need to be escaped so that they can be put into a
    // string literal.
    var escapes = {
        "'":      "'",
        '\\':     '\\',
        '\r':     'r',
        '\n':     'n',
        '\t':     't',
        '\u2028': 'u2028',
        '\u2029': 'u2029'
    };

    var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;

    // JavaScript micro-templating, similar to John Resig's implementation.
    // Underscore templating handles arbitrary delimiters, preserves whitespace,
    // and correctly escapes quotes within interpolated code.
    _.template = function(text, data, settings) {
        var render;
        settings = _.defaults({}, settings, _.templateSettings);

        // Combine delimiters into one regular expression via alternation.
        var matcher = new RegExp([
            (settings.escape || noMatch).source,
            (settings.interpolate || noMatch).source,
            (settings.evaluate || noMatch).source
        ].join('|') + '|$', 'g');

        // Compile the template source, escaping string literals appropriately.
        var index = 0;
        var source = "__p+='";
        text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
            source += text.slice(index, offset)
                .replace(escaper, function(match) { return '\\' + escapes[match]; });

            if (escape) {
                source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
            }
            if (interpolate) {
                source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
            }
            if (evaluate) {
                source += "';\n" + evaluate + "\n__p+='";
            }
            index = offset + match.length;
            return match;
        });
        source += "';\n";

        // If a variable is not specified, place data values in local scope.
        if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';

        source = "var __t,__p='',__j=Array.prototype.join," +
            "print=function(){__p+=__j.call(arguments,'');};\n" +
            source + "return __p;\n";

        try {
            render = new Function(settings.variable || 'obj', '_', source);
        } catch (e) {
            e.source = source;
            throw e;
        }

        if (data) return render(data, _);
        var template = function(data) {
            return render.call(this, data, _);
        };

        // Provide the compiled function source as a convenience for precompilation.
        template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';

        return template;
    };

    // Add a "chain" function, which will delegate to the wrapper.
    _.chain = function(obj) {
        return _(obj).chain();
    };

    // OOP
    // ---------------
    // If Underscore is called as a function, it returns a wrapped object that
    // can be used OO-style. This wrapper holds altered versions of all the
    // underscore functions. Wrapped objects may be chained.

    // Helper function to continue chaining intermediate results.
    var result = function(obj) {
        return this._chain ? _(obj).chain() : obj;
    };

    // Add all of the Underscore functions to the wrapper object.
    _.mixin(_);

    // Add all mutator Array functions to the wrapper.
    each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
        var method = ArrayProto[name];
        _.prototype[name] = function() {
            var obj = this._wrapped;
            method.apply(obj, arguments);
            if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
            return result.call(this, obj);
        };
    });

    // Add all accessor Array functions to the wrapper.
    each(['concat', 'join', 'slice'], function(name) {
        var method = ArrayProto[name];
        _.prototype[name] = function() {
            return result.call(this, method.apply(this._wrapped, arguments));
        };
    });

    _.extend(_.prototype, {

        // Start chaining a wrapped Underscore object.
        chain: function() {
            this._chain = true;
            return this;
        },

        // Extracts the result from a wrapped and chained object.
        value: function() {
            return this._wrapped;
        }

    });

}).call(this);

/**
 * Copyright (c) 2007-2012 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under MIT and GPL.
 * @author Ariel Flesler
 * @version 1.4.5 BETA
 */
;(function($){var h=$.scrollTo=function(a,b,c){$(window).scrollTo(a,b,c)};h.defaults={axis:'xy',duration:parseFloat($.fn.jquery)>=1.3?0:1,limit:true};h.window=function(a){return $(window)._scrollable()};$.fn._scrollable=function(){return this.map(function(){var a=this,isWin=!a.nodeName||$.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!isWin)return a;var b=(a.contentWindow||a).document||a.ownerDocument||a;return/webkit/i.test(navigator.userAgent)||b.compatMode=='BackCompat'?b.body:b.documentElement})};$.fn.scrollTo=function(e,f,g){if(typeof f=='object'){g=f;f=0}if(typeof g=='function')g={onAfter:g};if(e=='max')e=9e9;g=$.extend({},h.defaults,g);f=f||g.duration;g.queue=g.queue&&g.axis.length>1;if(g.queue)f/=2;g.offset=both(g.offset);g.over=both(g.over);return this._scrollable().each(function(){if(e==null)return;var d=this,$elem=$(d),targ=e,toff,attr={},win=$elem.is('html,body');switch(typeof targ){case'number':case'string':if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)){targ=both(targ);break}targ=$(targ,this);if(!targ.length)return;case'object':if(targ.is||targ.style)toff=(targ=$(targ)).offset()}$.each(g.axis.split(''),function(i,a){var b=a=='x'?'Left':'Top',pos=b.toLowerCase(),key='scroll'+b,old=d[key],max=h.max(d,a);if(toff){attr[key]=toff[pos]+(win?0:old-$elem.offset()[pos]);if(g.margin){attr[key]-=parseInt(targ.css('margin'+b))||0;attr[key]-=parseInt(targ.css('border'+b+'Width'))||0}attr[key]+=g.offset[pos]||0;if(g.over[pos])attr[key]+=targ[a=='x'?'width':'height']()*g.over[pos]}else{var c=targ[pos];attr[key]=c.slice&&c.slice(-1)=='%'?parseFloat(c)/100*max:c}if(g.limit&&/^\d+$/.test(attr[key]))attr[key]=attr[key]<=0?0:Math.min(attr[key],max);if(!i&&g.queue){if(old!=attr[key])animate(g.onAfterFirst);delete attr[key]}});animate(g.onAfter);function animate(a){$elem.animate(attr,f,g.easing,a&&function(){a.call(this,e,g)})}}).end()};h.max=function(a,b){var c=b=='x'?'Width':'Height',scroll='scroll'+c;if(!$(a).is('html,body'))return a[scroll]-$(a)[c.toLowerCase()]();var d='client'+c,html=a.ownerDocument.documentElement,body=a.ownerDocument.body;return Math.max(html[scroll],body[scroll])-Math.min(html[d],body[d])};function both(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
/* little helper function for get parameters */
function $_GET(param) {
	var vars = {};
	window.location.href.replace( location.hash, '' ).replace( 
		/[?&]+([^=&]+)=?([^&]*)?/gi, // regexp
		function( m, key, value ) { // callback
			vars[key] = value !== undefined ? value : '';
		}
	);

	if ( param ) {
		return vars[param] ? vars[param] : null;	
	}
	return vars;
}

function sort_li(a, b){
    return ($(b).data('distance')) < ($(a).data('distance')) ? 1 : -1;
}
/**
 * adds support for template mixins to  underscore.js
 * @see https://github.com/rotundasoftware/underscore-template-helpers
 */
(function () {
    "use strict";
    var originalUnderscoreTemplateFunction = _.template,
        templateHelpers = {};

    _.mixin({
        addTemplateHelpers : function (newHelpers) {
            _.extend(templateHelpers, newHelpers);
        },

        template : function (text, data, settings) {
            // replace the built in _.template function with one that supports the addTemplateHelpers
            // function above. Basically the combo of the addTemplateHelpers function and this new
            // template function allows us to mix in global "helpers" to the data objects passed
            // to all our templates when they render. This replacement template function just wraps
            // the original _.template function, so it sould be pretty break-resistent moving forward.

            if (data) {
                // if data is supplied, the original _.template function just returns the raw value of the
                // render function (the final rentered html/text). So in this case we just extend
                // the data param with our templateHelpers and return raw value as well.

                _.defaults(data, templateHelpers); // extend data with our helper functions
                return originalUnderscoreTemplateFunction.apply(this, arguments); // pass the buck to the original _.template function
            }

            var template = originalUnderscoreTemplateFunction.apply(this, arguments);

            return function (data) {
                data = _.defaults({}, data, templateHelpers);
                return template.call(this, data);
            };
        }
    });
})();

// useful helper functions for underscore templates
_.addTemplateHelpers({
    // inline conditions
    iff : function (condition, outputString) {
        "use strict";
        return condition ? outputString : "";
    },
    // email tag helper
    emailTag: function (address, title) {
        "use strict";
        var content = '',
            titleAttribute = (title ? 'title="' + title + '"' : '');

        if (address) {
            content = '<a href="mailto:' + address + '" ' + titleAttribute + '>' + address + '</a>';
        }

        return content;
    },

    // generates a link
    linkTag: function (url, target) {
        "use strict";
        var content = '',
            targetAttribute = (target ? 'target="' + target + '"' : '');
        if (url) {
            content = '<a href="' + url + '" ' + targetAttribute + '>' + url + '</a>';
        }
        return content;
    },
    clearPrems: function(categories) {
        "use strict";
        // scooter
        if($.grep(categories, function(e){ return e.uid === 3; }).length)
            categories = $.grep(categories, function(o) { return o.uid === 1; }, true);
        // quad
        if($.grep(categories, function(e){ return e.uid === 7; }).length)
            categories = $.grep(categories, function(o) { return o.uid === 5; }, true);
        return categories;
    },
});

(function ($, window, document, undefined) {
    "use strict";

    // Create the defaults once
    var markerClusterer = null;
    var isDraggable = !('ontouchstart' in document.documentElement);
    var pluginName = 'AkGooglemaps',
        defaults = {
            mapConfig: {
                mapTypeId: google.maps.MapTypeId.ROADMAP,
             //   draggable: isDraggable,
            //    scrollwheel: false
            }
        };

    // The actual plugin constructor
    function AkGooglemaps(element, options) {
        this.element = element;
        // first param is true to merge nested objects
        this.options = $.extend(true, {}, defaults, options);

        this.defaults = defaults;
        this.name = pluginName;

        this.map = null;
        this.icons = {};
        this.shadows = {};
        this.addressList = this.options.addressList;
        this.addressListSlider = null;
        this.addressWrap = this.options.addressWrap;
        this.categoryList = this.options.categoryList;
        this.attributeList = this.options.attributeList;
        this.attributeListWrap = this.options.attributeListWrap;
        this.findNearby = this.options.findNearby;
        this.infoWindow = new google.maps.InfoWindow({
            pixelOffset: new google.maps.Size(0,30)
        });
        this.directionRenderer = null;
        this.filterCategories = null;
        this.filterAttribute = null;
        this.data = {
            icons: [],
            addresses: [],
            categories: [],
            messages: []
        };

        this.init();
    }

    AkGooglemaps.prototype = {
        init: function () {
            // active 2nd Searchbar
            $(".mapFindNearByFilter").removeClass("hidden");
            this.map = new google.maps.Map(this.element, this.options.mapConfig);
            $.get(this.options.dataUrl, $.proxy(this.dataCallback, this));
            this.addAppEventListener();
        },

        dataCallback: function (data) {
            var self = this;

            this.data = data;
            this.resolveCategoryAndAttributeRelations(data.addresses, data.categories, data.attributes);
            this.addIconsToMap(data.icons);
            this.addMarkersToMap(data.addresses);
            this.addCategoryFilter(data.categories);
            this.addAttributeFilter(data.attributes);
            this.prefillFilterConditionsForCategory();
            this.setupRouting();
            this.addEventListenerForDistanceSearch();
            if (this.options.autoResize && this.options.autoResize === true) {
                this.autoDimensions();
                google.maps.event.addDomListener(window, 'resize', function () {
                    // get the plugin instance and call the audoDimensions method
                    $(self.element).AkGooglemaps('autoDimensions');
                });
            }
            if (this.options.wholeWorld && this.options.wholeWorld === true) {
                this.showWholeWorld();
            }

            // check for hash value
            self.handleDeeplink();
            //Added by: fweber
            //Hide all Marker!
            //self.hideMarker();

            // added by: Awildenrother
            // ShowSearch Result by External Formular
			if( $_GET( 'hsearch' ) && $_GET( 'hsearch' ).length && $_GET( 'hsearch' ) != "") {
	         $(this.findNearby.searchInput).val( $_GET( 'hsearch' ));
	         $(this.findNearby.search).trigger('click');
	        } else {
	            // trigger GeoPos on Loading
                $(this.findNearby.searchInputGeoPos).trigger('click');
            }
            // track Clicks for Filters
            $(".mapFindNearByFilter ul li").click(function (e) {
                if(!$(this).hasClass("selected")) {
                    $(this).parent().find(".selected").removeClass("selected");
                    $(this).addClass("selected");

                    var filters = Array();
                    filters.push($(this).data("value"));

                    switch($(this).parent().data("type")) {
                        case 'attribute':
                            self.filterAttribute = filters;
                            break;
                        case 'distance':
                            // do nothing at all...
                            //self = filters;
                            break;
                        case 'category':
                            self.filterCategories = filters;
                            break;
                    }

                    self.showAddressesWithFilter();
                }
                $(this).parent().toggleClass("closed");
                $(this).parent().prev().toggleClass("open");

            });
            $(".mapFindNearByFilter .select > span").click(function (e) {
                $(this).next().find(".selected").trigger("click");
            });
        },

        handleDeeplink: function () {
            var self = this,
                test,
                selectedAddress;

            if (document.location.hash && document.location.hash.substr(0, 9) === '#address-') {
                test = parseInt(document.location.hash.substr(9), 10);

                if (test > 0) {
                    selectedAddress = _.findWhere(this.data.addresses, {uid: test});

                    if (selectedAddress) {
                        self.map.setCenter(selectedAddress.marker.getPosition());
                        self.map.setZoom(8);
                        self.openInfoWindow(selectedAddress);
                        this.routeSetTarget(selectedAddress);
                    }
                }
            }
        },

        getMessage: function (key) {
            if (this.data.messages[key]) {
                return this.data.messages[key];
            }
            return '';
        },

        /*
	    * Hide marker
	    * added by: fweber
        */
        hideMarker: function() {
	        var self = this;
            var markers = [];
            markerClusterer.clearMarkers();
            $.each(self.data.addresses, function () {
	        	this.marker.setMap(null);
	        });
	        self.addressList.addClass('hidden');
        },

        /*
	    * Show marker
	    * added by: fweber
        */
        showMarker: function() {
	        var self = this;
	        var markers = [];
            markerClusterer.clearMarkers();
	        $.each(self.data.addresses, function () {
	        	if(this.marker.visible == true) {
                    this.marker.setMap(self.map);
                    markers.push(this.marker);
	        	}
	        });
            markerClusterer.addMarkers(markers);
			self.addressList.removeClass('hidden');
        },

        // when attributeFilter is invoked first, these data needs to be set
        prefillFilterConditionsForCategory: function () {
            this.filterCategories = _.pluck(this.data.categories, 'uid');
        },

        /**
         * called externally
         */
        showAddressesWithFilter: function () {
            var self = this,
                filterCategories,
                filterAttribute,
                address,
                addressShouldBeDisplayed = false,
                visibleAddresses = [],
                distanceFilterUsed = false,
                bounds = new google.maps.LatLngBounds(),
               // maxDistance = this.findNearby.distance.val();
                maxDistance = this.findNearby.distance.find(".selected").data("value");

            if( self.addressListSlider ) {
                self.addressListSlider.destroy();
                self.addressListSlider.children().remove();
            }
            // casting the given entries to integer
            if (this.filterCategories) {
                filterCategories = $.map(this.filterCategories, function (num) {
                    return parseInt(num, 10);
                });
            }

            if (this.filterAttribute) {
                filterAttribute = parseInt(this.filterAttribute, 10);
            }

            // activate distance filtering
            if (self.isDefined(self.findNearby.resultMarker) && self.findNearby.resultMarker.getMap()) {
                distanceFilterUsed = true;
                self.map.setZoom(12);
                bounds.extend(self.findNearby.resultMarker.getPosition());
            }

            $.each(self.data.addresses, function () {
                var visibleThroughCategory = false,
                    visibleThroughAttribute = false;

                address = this;
                addressShouldBeDisplayed = false;

				if(address.categories.length && filterCategories[0] != -1) {
	                $.each(address.categories, function () {
	                    var category = this;
	                    if ($.inArray(category.uid, filterCategories) > -1) {
	                        visibleThroughCategory = true;
	                        // break the each loop by returning false;
	                        return false;
	                    }
	                });
	            } else {
		             visibleThroughCategory = true;
	            }

                if (!filterAttribute) {
                    visibleThroughAttribute = true;
                } else {
                    $.each(address.attributes, function () {
                        var attribute = this;
                        if (attribute.uid === filterAttribute) {
                            visibleThroughAttribute = true;
                            return false;
                        }
                    });
                }

                // so the filter and the category say, we should display the address
                if (visibleThroughCategory && visibleThroughAttribute) {
                    addressShouldBeDisplayed = true;
                }


                // now test if there is a distance restriction, but only if no other restriction is in effect
                var distance = 0;
                if (addressShouldBeDisplayed === true && distanceFilterUsed === true) {
                    distance = self.getDistance(address.marker, self.findNearby.resultMarker);
                    if ( distance > maxDistance) {
                        addressShouldBeDisplayed = false;
                    }
                }

                if (addressShouldBeDisplayed === true) {
                    address.marker.setVisible(true);
                    // needed for the message
                    visibleAddresses.push(address);
                    if (distanceFilterUsed === true) {
                        bounds.extend(address.marker.getPosition());
                    }

                    if (address.hideInList === false) {
                        address.distance = distance;
                        address.listEntry = $(self.options.listEntryRenderer ? self.options.listEntryRenderer(address) : address.listText);
                        address.listEntry.appendTo(self.addressList);

                        address.listEntry.on("click", '.calculateRoute', function (e) {
                            e.preventDefault();
                            self.routeSetTarget(address);
                        });
                        self.addEventListenerForAddress(address);
                    }

                } else {
                    if (address.markerIsActive) {
                        address.markerIsActive = false;
                        self.infoWindow.close();
                    }
                    address.marker.setVisible(false);
                    if (address.listEntry) {
                        address.listEntry = null;
                    }
                }
            });

            if (distanceFilterUsed === true) {
                if (visibleAddresses.length === 0) {
                    self.map.setZoom(10);
                } else {
                    self.map.fitBounds(bounds);
                    self.setZoomLevelAfterFitbounds();
                }
            }

			//Added by: fweber
			//Show Marker only when search!
            self.showMarker();
            self.showHideNoAddressesMessage(visibleAddresses);
            markerClusterer.repaint();
            if(self.addressListSlider)
                self.addressListSlider.destroy();
            // sort elements by Distance
            $(".mapAddressList li").sort(sort_li).appendTo('.mapAddressList');

            self.addressListSlider = $(self.addressList).lightSlider({
                item: 4,
                loop: true,
                controls: true,
                pager: false,
                gallery: false,
                slideMargin: 0,
                galleryMargin: 0,
                thumbMargin: 0,
                mode: 'slide',
                enableTouch: false,
                enableDrag: false,
                arrowPos: 'inside',
                responsive : [
                    {
                        breakpoint: 1024,
                        settings: { item: 2,
                            enableTouch: true,
                            enableDrag: true,
                        }
                    },  {
                        breakpoint: 465,
                        settings: {
                            item: 1,
                            enableTouch: true,
                            enableDrag: true,
                        }
                    }
                ]

            });

        },

        showHideNoAddressesMessage: function (addresses) {
            var self = this,
                targetElement = $(self.addressWrap).find('.mapNoAddresses');

            if (addresses.length === 0) {
                self.addressList.addClass('hidden');
                targetElement.removeClass('hidden');
            } else {
                self.addressList.removeClass('hidden');
                targetElement.addClass('hidden');
            }
        },

        setZoomLevelAfterFitbounds: function () {
            var self = this,
                currentZoom;

            currentZoom = self.map.getZoom();
            currentZoom = (currentZoom - 1);
            currentZoom = Math.min(16, currentZoom);

            self.map.setZoom(currentZoom);
        },

        resolveCategoryAndAttributeRelations: function (addresses, categories, attributes) {
            $.each(addresses, function () {
                var address = this,
                    selectedCategories = $.map(address.categories.split(','), function (num) { return parseInt(num, 10); }),
                    selectedAttributes = $.map(address.attributes.split(','), function (num) {return parseInt(num, 10); });
                if (selectedCategories.length > 0) {
                    address.categories = $.grep(categories, function (category) {
                        return ($.inArray(category.uid, selectedCategories) > -1);
                    });
                }
                if (selectedAttributes.length > 0) {
                    address.attributes = $.grep(attributes, function (attribute) {
                        return ($.inArray(attribute.uid, selectedAttributes) > -1);
                    });
                }
            });
        },

        addCategoryFilter: function (categories) {
            var self = this;
            $.each(categories, function () {
                var category = this;
                category.listEntry = $(self.isDefined(self.options.categoryEntryRenderer) ? self.options.categoryEntryRenderer(category, self.icons) : category.title);
                category.listEntry.appendTo(self.categoryList);
            });
        },

        addAttributeFilter: function (attributes) {
            var self = this;

            if (attributes.length === 0) {
                self.attributeListWrap.hide();
            } else {
                $.each(attributes, function () {
                    var attribute = this;
                    attribute.listEntry = $(self.isDefined(self.options.attributeEntryRenderer) ? self.options.attributeEntryRenderer(attribute) : attribute.title);
                    attribute.listEntry.appendTo(self.attributeList);
                });
            }
        },

        setupRouting: function () {
            var self = this;
            $(self.options.calculateRouteButton).on('click', function (e) {
                e.preventDefault();

                // check if both inputs are filled out
                var waypoints = $(self.options.mapRoutes).find('input.waypoint').filter(function () { return $(this).val() !== ""; });
                if (waypoints.length < 2) {
                    self.showRoutingError(self.getMessage('start_address_missing'));
                } else {
                    self.showRoute(waypoints.get(0), waypoints.get(1));
                }

                e.stopPropagation();
            });
        },

        showRoute: function (startInput, endInput) {
            var self = this,
                currentDirectionsDisplay,
                start,
                end,
                directionRequest,
                directionService = new google.maps.DirectionsService();

            if ($(startInput).data('address')) {
                start = $(startInput).data('address').latitude + ' ' + $(startInput).data('address').longitude;
            } else {
                start = $(startInput).val();
            }

            if ($(endInput).data('address')) {
                end = $(endInput).data('address').latitude + ' ' + $(endInput).data('address').longitude;
            } else {
                end = $(endInput).val();
            }

            directionRequest = {
                origin: start,
                destination: end,
                travelMode: google.maps.TravelMode.DRIVING
            };

            self.clearDirections();
            self.infoWindow.close();


            directionService.route(directionRequest, function (DirectionsResult, DirectionsStatus) {
                if (DirectionsStatus === 'OK') {
                    currentDirectionsDisplay = new google.maps.DirectionsRenderer({
                        map: self.map,
                        panel: $(self.options.routingPanel).get(0),
                        draggable: true,
                        directions: DirectionsResult
                    });
                    self.directionRenderer = currentDirectionsDisplay;
                } else if (DirectionsStatus === 'NOT_FOUND') {
                    self.showRoutingError(self.getMessage('directions_not_found'));
                    _.delay(function () {self.showRoutingError(); }, 5000);
//                        window.setTimeout(function () {
//                            $('#mapDirectionErrorBox').hide().text('');
//                        }, errorTimeOut);
                }
            });
        },

        clearDirections: function () {
            var self = this;
            // clear route, but do not kill connection to map
            if (self.isDefined(self.directionRenderer)) {
                self.directionRenderer.set('directions', null);
            }
            self.clearRoutingErrors();
        },

        showRoutingError: function (message) {
            var self = this;
            if (message) {
                $(self.options.mapRoutes).find('.routingErrors').html(message).show();
            } else {
                $(self.options.mapRoutes).find('.routingErrors').hide();
            }
        },

        clearRoutingErrors: function () {
            var self = this;
            $(self.options.mapRoutes).find('.routingErrors').html('').hide();
        },

        addIconsToMap: function (icons) {
            var self = this;
            $.each(icons, function () {
                var anchorX, anchorY, shadowAnchorX, shadowAnchorY;

                self.icons[this.uid] = {
                    url: this.icon,
                    size: new google.maps.Size(parseInt(this.width), parseInt(this.height))
                };

                anchorX = (self.isDefined(this.anchorX) ? this.anchorX : Math.round(this.width / 2));
                anchorY = (self.isDefined(this.anchorY) ? this.anchorY : this.height);

                self.icons[this.uid].anchor = new google.maps.Point(parseInt(anchorX), parseInt(anchorY));

                if (this.shadow) {
                    self.shadows[this.uid] = {
                        url: this.shadow,
                        size: new google.maps.Size(this.shadowWidth, this.shadowHeight)
                    };

                    shadowAnchorX = (self.isDefined(this.shadowAnchorX) ? this.shadowAnchorX : Math.round(this.width / 2));
                    shadowAnchorY = (self.isDefined(this.shadowAnchorY) ? this.shadowAnchorY : this.shadowHeight);
                    self.shadows[this.uid].anchor = new google.maps.Point(shadowAnchorX, shadowAnchorY);
                }
            });
        },

        isDefined: function (testValue) {
            if (testValue === undefined || testValue === null) {
                return false;
            }
            return true;
        },

        addMarkersToMap: function (addresses) {
            var self = this;
            var markers = [];
            /*
            var goldStar = {
                path: 'M 125,5 155,90 245,90 175,145 200,230 125,180 50,230 75,145 5,90 95,90 z',
                fillColor: 'black',
                fillOpacity: 0.8,
                scale: 0.1,
                strokeColor: 'black',
                strokeWeight: 1
            };
            */
            $.each(addresses, function () {
                var address = this;
                var icon = null;
                icon = "/typo3conf/ext/ak_googlemaps/Resources/Public/Icons/kymco_pointer.png";

                if(address.icon && self.icons[address.icon] ) {
                    icon = self.icons[address.icon];
                } else if (address.categories) {
                    $.each(address.categories, function () {
                        if(this.icon && self.icons[this.icon]) {
                            icon = self.icons[this.icon];
                            //console.log(icon);
                        }
                    });
                }

                //console.log(address);
                address.marker = new google.maps.Marker({
                    position: new google.maps.LatLng(address.latitude, address.longitude),
                    map: self.map,
                    title: address.title,
                    //icon: goldStar,
                    icon: icon,
                    shadow: (address.icon && self.shadows[address.icon] ? self.shadows[address.icon] : null)
                });

                //console.log(address.marker);
                markers.push(address.marker);

                // add an entry to the address list
                /*
                if (address.hideInList === false) {
                    address.listEntry = $(self.options.listEntryRenderer ? self.options.listEntryRenderer(address) : address.listText);
                    address.listEntry.appendTo(self.addressList);

                    address.listEntry.on("click", '.calculateRoute', function (e) {
                        e.preventDefault();
                        self.routeSetTarget(address);
                    });
                }
                 */
                self.addEventListenerForAddress(address);

            });

            var clusterStyles = [
                {
                    textColor: 'white',
                    textSize: 15,
                    url: '/typo3conf/ext/ak_googlemaps/Resources/Public/Icons/kymco_pointer_count.png',
                    height: 34,
                    width: 30,
                  //  anchor: [-70,0],
                 //  iconAnchor: [40,56]
                }
            ];
            var mcOptions = {
                gridSize: 60,
                maxZoom: 8,
                averageCenter: true,
                styles: clusterStyles
            };
            markerClusterer = new MarkerClusterer(this.map , markers, mcOptions);
        },

        addEventListenerForAddress: function (address) {
            var self = this;
            google.maps.event.addListener(address.marker, 'click', function () {
                $(self.element).trigger('clicked_marker', address);
                self.openInfoWindow(address);
            });

            if (address.listEntry) {
                google.maps.event.addDomListener(address.listEntry.get(0), 'click', function () {
                    self.map.setCenter(address.marker.getPosition());
                    self.openInfoWindow(address);
                });
            }
        },

        openInfoWindow: function (address) {
            var self = this;
            address.markerIsActive = true;
            self.infoWindow.close();

            self.infoWindow.setContent(self.options.infoWindowRenderer ? self.options.infoWindowRenderer(address) : (address.bubbleText ? address.bubbleText : address.listText));
            self.infoWindow.open(self.map, address.marker);

            $('.getDirections').on('click', function(e) {
                e.preventDefault();
                self.routeSetTarget(address);
            });


        },

        autoDimensions: function () {
            var self = this,
                $parentElement = $(self.element).parent(),
                parentContainerWidth = $parentElement.width(),
                containerHeight = $(self.element).height(),
                filterHeight = $(self.categoryList).parents('.mapFilter').outerHeight(),
                addressesWidth = $(self.addressWrap).outerWidth()+$(self.addressWrap).css("margin-right"),
                viewportHeight = $(window).height(),
                center = self.map.getCenter();

            if (self.options.heightAdjustment) {
                viewportHeight = viewportHeight - self.options.heightAdjustment;
            }

            // use full width for the map
            if ($parentElement.hasClass('overlayAddressesRight')) {
                if (parentContainerWidth > self.options.minWidth) {
                    $(self.element).width(parentContainerWidth);
                }
                if (viewportHeight > self.options.minHeight) {
                    $(self.element).height(viewportHeight);
                    $parentElement.height(viewportHeight);
                }
                //self.addressList.height(self.addressList.parents('.mapAddressesWrap').height() - filterHeight);

                //self.options.mapRoutes.height(self.addressList.parents('.mapAddressesWrap').height());

            } else {
                // resize the map width too 100% - the width for the addresses
                if (parentContainerWidth > self.options.minWidth) {
                    $(self.element).width(parentContainerWidth - addressesWidth);
                }
/*
                if (viewportHeight > self.options.minHeight) {
                    $(self.element).height(viewportHeight);
                    $parentElement.height(viewportHeight);
                    containerHeight = viewportHeight;
                }
*/
               // self.addressList.height(containerHeight - filterHeight);
                //TODO: implement routing for this option
            }

            google.maps.event.trigger(self.map, "resize");

            // restore the center
            self.map.setCenter(center);
        },

        showWholeWorld: function () {
            var bounds, l, r;

            l = new google.maps.LatLng(0, -180);
            r = new google.maps.LatLng(0, 180);

            this.map.setZoom(20);
            bounds = new google.maps.LatLngBounds(l, r);
            this.map.fitBounds(bounds);
        },


        browserGeocodeSuccess: function(position) {
            var self = this,
            //searchInput = //self.findNearby.searchInput,
            searchInput = self.findNearby.searchInputGeoPos.parent().find("input"),
            coordinates;

            coordinates = new google.maps.LatLng(
                position.coords.latitude,
                position.coords.longitude
            );

            var geocoder = new google.maps.Geocoder();
            var geocoderRequest = {
                location: coordinates
            };

            geocoder.geocode(geocoderRequest, function (geocoderResult, geocoderStatus) {
                $(".detectingLocation").remove();
                if (geocoderStatus === 'OK') {
                    // Inputfeld mit der gefundenen Addresse befuellen
                    searchInput.val(geocoderResult[0].formatted_address);

                    self.map.setCenter(coordinates);
                    if (self.findNearby.resultMarker) {
                        self.findNearby.resultMarker.setPosition(coordinates);
                        self.findNearby.resultMarker.setTitle(geocoderResult[0].formatted_address);
                        self.findNearby.resultMarker.setMap(self.map);
                    } else {
                        self.findNearby.resultMarker = new google.maps.Marker({
                            map: self.map,
                            position: geocoderResult[0].geometry.location,
                            title: geocoderResult[0].formatted_address,
                            animation: google.maps.Animation.DROP,
                            icon: "https://maps.google.com/mapfiles/ms/micons/blue-dot.png",
                            //                            shadow: "https://maps.google.com/mapfiles/ms/micons/msmarker.shadow.png",
                            zIndex: 1
                        });
                    }
                    self.showAddressesWithFilter();

                } else {
                    // todo: show message for invalid address
                }
            });
        },

        browserGeocodeError: function() {
            if($(".detectingLocation").length) {
                $(".detectingLocation").remove();
               // $(".mapRoutes, .mapFindNearByWrap").append("<span class='detectingLocation locErr'>"+self.options.determineCurrentPositionMessageFailed+"</span>");
               // setTimeout(function () {
               //     $(".locErr").remove();
               // }, 3000);
            }
        },

        doBrowserGeocode: function (e) {
            e.preventDefault();
            var self = this;
            // lets do it...
            $(".mapRoutes, .mapFindNearByWrap").append("<span class='detectingLocation'>"+self.options.determineCurrentPositionMessage+"</span>");
            navigator.geolocation.getCurrentPosition(
                $.proxy(self.browserGeocodeSuccess, self),
                self.browserGeocodeError,
                {maximumAge:60000, timeout:5000, enableHighAccuracy:true}
            );
            // well Firefox does not give any Feedback.. so kill request after 15 sec... https://bugzilla.mozilla.org/show_bug.cgi?id=675533
            setTimeout(function(){ self.browserGeocodeError(); }, 15000);
        },

        doDistanceSearch: function (e) {
            e.preventDefault();
            var self = this,
                searchInput = self.findNearby.searchInput,
                searchInputValue = searchInput.val(),
                coordinates;

            if (!searchInputValue) {
                self.removeOldResultMarker();
                searchInput.addClass("error").focus();
                searchInput.one("change keypress paste focus textInput input", function (){
                    searchInput.removeClass("error");
                });
            } else {
                var geocoder = new google.maps.Geocoder();
                var geocoderRequest = {
                    address: searchInputValue,
                    region: self.options.baseCountryDef,

                };

                geocoder.geocode(geocoderRequest, function (geocoderResult, geocoderStatus) {
                    if (geocoderStatus === 'OK') {
                        // Inputfeld mit der gefundenen Addresse befuellen
                        searchInput.val(geocoderResult[0].formatted_address);
                        coordinates = new google.maps.LatLng(
                            geocoderResult[0].geometry.location.lat(),
                            geocoderResult[0].geometry.location.lng()
                        );

                        self.map.setCenter(coordinates);

                        if (self.findNearby.resultMarker) {
                            self.findNearby.resultMarker.setPosition(coordinates);
                            self.findNearby.resultMarker.setTitle(geocoderResult[0].formatted_address);
                            self.findNearby.resultMarker.setMap(self.map);
                        } else {
                            self.findNearby.resultMarker = new google.maps.Marker({
                                map: self.map,
                                position: geocoderResult[0].geometry.location,
                                title: geocoderResult[0].formatted_address,
                                animation: google.maps.Animation.DROP,
                                icon: "https://maps.google.com/mapfiles/ms/micons/blue-dot.png",
    //                            shadow: "https://maps.google.com/mapfiles/ms/micons/msmarker.shadow.png",
                                zIndex: 1
                            });
                        }

                        self.showAddressesWithFilter();

                    } else {
                        alert(self.options.determineCurrentPositionMessageNotFound);
                        // todo: show message for invalid address
                    }
                });
            }
        },

        /**
         * remove a previously set marker
         */
        removeOldResultMarker: function () {
            var self = this;
            if (self.findNearby.resultMarker) {
                self.findNearby.resultMarker.setMap(null);
            }
        },

        resetDistanceSearch: function (e) {
            e.preventDefault();
            var self = this;
            self.findNearby.searchInput.val('').focus();
            self.removeOldResultMarker();
            self.showAddressesWithFilter();
         //   self.hideMarker();
        },

        addEventListenerForDistanceSearch: function () {
            var self = this;
            // submit with enter
            self.findNearby.searchInput.on('keypress', function (e) {
                if (e.keyCode === 13) {
                    self.findNearby.search.trigger('click');
                }
            });
            // try to get GeoData via Browser
            self.findNearby.searchInputGeoPos.on('click', $.proxy(self.doBrowserGeocode, self));

            self.findNearby.search.on('click', $.proxy(self.doDistanceSearch, self));
            // do the distance search when the distance select changes, but only if the input is not empty
            /*self.findNearby.distance.on('change', function (e) {
                if (self.findNearby.searchInput.val() !== '') {
                    self.doDistanceSearch(e);
                }
            });*/
            self.findNearby.distance.find("span").on('click', function (e) {
             if (self.findNearby.searchInput.val() !== '') {
             self.doDistanceSearch(e);
             }
             });
            self.findNearby.reset.on('click', $.proxy(self.resetDistanceSearch, self));
        },

        routeSetTarget: function (address) {
            var self = this;
            self.clearRoutingErrors();
            // clear any previous routes
            self.options.targetWaypoint.val(address.titleSingleLine).data('address', address);

            // little delay for focus so it works for the first time
            setTimeout($.proxy(function () {
                self.options.startWaypoint.focus();
            }, $(this)), 10);


            $('.mapEntries').hide();
            self.options.addressWrap.addClass('directionsActive');
            $('.mapRoutes').show();

            $('.mapRoutes').find(".usergeoCodePos").trigger('click');
        },

        closeDirections: function () {
            var self = this;
            self.clearDirections();
            $('.mapRoutes').hide();
            self.options.addressWrap.removeClass('directionsActive');
            $('.mapEntries').show();
        },

        addAppEventListener: function () {
            var self = this;
            self.options.closeRoute.on("click", function (e) {
                e.preventDefault();
                self.closeDirections();
            });
        },

        /**
         * credits to http://snipplr.com/view/25479/
         * slightly modified, because we only need the getDistance in km
         *
         * @param address
         * @param point
         * @returns {number}
         */
        getDistance: function (address, point) {
            var lat1 = address.getPosition().lat(),
                lon1 = address.getPosition().lng(),
                lat2 = point.getPosition().lat(),
                lon2 = point.getPosition().lng(),
                R = 6371, // km (change this constant to get miles)
                dLat = (lat2 - lat1) * Math.PI / 180,
                dLon = (lon2 - lon1) * Math.PI / 180,
                a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
                    Math.sin(dLon / 2) * Math.sin(dLon / 2),
                c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

            return Math.round(R * c);
        }
    };

    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[pluginName] = function (options) {
        var args = arguments,
            returns;

        if (options === undefined || typeof options === 'object') {
            return this.each(function () {
                if (!$.data(this, 'plugin_' + pluginName)) {
                    $.data(this, 'plugin_' + pluginName, new AkGooglemaps(this, options));
                }
            });

        } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
            returns = null;
            this.each(function () {
                var instance = $.data(this, 'plugin_' + pluginName);
                if (instance instanceof AkGooglemaps && typeof instance[options] === 'function') {
                    returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
                }

                if (options === 'destroy') {
                    $.data(this, 'plugin_' + pluginName, null);
                }
            });

            return returns !== undefined ? returns : this;
        }
    };
})($, window, document);

/**
 * Created by schuessler on 25.08.2016.
 */
// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @externs_url http://closure-compiler.googlecode.com/svn/trunk/contrib/externs/maps/google_maps_api_v3_3.js
// ==/ClosureCompiler==

/**
 * @name MarkerClusterer for Google Maps v3
 * @version version 1.0
 * @author Luke Mahe
 * @fileoverview
 * The library creates and manages per-zoom-level clusters for large amounts of
 * markers.
 * <br/>
 * This is a v3 implementation of the
 * <a href="http://gmaps-utility-library-dev.googlecode.com/svn/tags/markerclusterer/"
 * >v2 MarkerClusterer</a>.
 */

/**
 * 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.
 */


/**
 * A Marker Clusterer that clusters markers.
 *
 * @param {google.maps.Map} map The Google map to attach to.
 * @param {Array.<google.maps.Marker>=} opt_markers Optional markers to add to
 *   the cluster.
 * @param {Object=} opt_options support the following options:
 *     'gridSize': (number) The grid size of a cluster in pixels.
 *     'maxZoom': (number) The maximum zoom level that a marker can be part of a
 *                cluster.
 *     'zoomOnClick': (boolean) Whether the default behaviour of clicking on a
 *                    cluster is to zoom into it.
 *     'averageCenter': (boolean) Wether the center of each cluster should be
 *                      the average of all markers in the cluster.
 *     'minimumClusterSize': (number) The minimum number of markers to be in a
 *                           cluster before the markers are hidden and a count
 *                           is shown.
 *     'styles': (object) An object that has style properties:
 *       'url': (string) The image url.
 *       'height': (number) The image height.
 *       'width': (number) The image width.
 *       'anchor': (Array) The anchor position of the label text.
 *       'textColor': (string) The text color.
 *       'textSize': (number) The text size.
 *       'backgroundPosition': (string) The position of the backgound x, y.
 *       'iconAnchor': (Array) The anchor position of the icon x, y.
 * @constructor
 * @extends google.maps.OverlayView
 */
function MarkerClusterer(map, opt_markers, opt_options) {
    // MarkerClusterer implements google.maps.OverlayView interface. We use the
    // extend function to extend MarkerClusterer with google.maps.OverlayView
    // because it might not always be available when the code is defined so we
    // look for it at the last possible moment. If it doesn't exist now then
    // there is no point going ahead :)
    this.extend(MarkerClusterer, google.maps.OverlayView);
    this.map_ = map;

    /**
     * @type {Array.<google.maps.Marker>}
     * @private
     */
    this.markers_ = [];

    /**
     *  @type {Array.<Cluster>}
     */
    this.clusters_ = [];

    this.sizes = [53, 56, 66, 78, 90];

    /**
     * @private
     */
    this.styles_ = [];

    /**
     * @type {boolean}
     * @private
     */
    this.ready_ = false;

    var options = opt_options || {};

    /**
     * @type {number}
     * @private
     */
    this.gridSize_ = options['gridSize'] || 60;

    /**
     * @private
     */
    this.minClusterSize_ = options['minimumClusterSize'] || 2;


    /**
     * @type {?number}
     * @private
     */
    this.maxZoom_ = options['maxZoom'] || null;

    this.styles_ = options['styles'] || [];

    /**
     * @type {string}
     * @private
     */
    this.imagePath_ = options['imagePath'] ||
        this.MARKER_CLUSTER_IMAGE_PATH_;

    /**
     * @type {string}
     * @private
     */
    this.imageExtension_ = options['imageExtension'] ||
        this.MARKER_CLUSTER_IMAGE_EXTENSION_;

    /**
     * @type {boolean}
     * @private
     */
    this.zoomOnClick_ = true;

    if (options['zoomOnClick'] != undefined) {
        this.zoomOnClick_ = options['zoomOnClick'];
    }

    /**
     * @type {boolean}
     * @private
     */
    this.averageCenter_ = false;

    if (options['averageCenter'] != undefined) {
        this.averageCenter_ = options['averageCenter'];
    }

    this.setupStyles_();

    this.setMap(map);

    /**
     * @type {number}
     * @private
     */
    this.prevZoom_ = this.map_.getZoom();

    // Add the map event listeners
    var that = this;
    google.maps.event.addListener(this.map_, 'zoom_changed', function() {
        var zoom = that.map_.getZoom();

        if (that.prevZoom_ != zoom) {
            that.prevZoom_ = zoom;
            that.resetViewport();
        }
    });

    google.maps.event.addListener(this.map_, 'idle', function() {
        that.redraw();
    });

    // Finally, add the markers
    if (opt_markers && opt_markers.length) {
        this.addMarkers(opt_markers, false);
    }
}


/**
 * The marker cluster image path.
 *
 * @type {string}
 * @private
 */
MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_PATH_ = '../images/m';


/**
 * The marker cluster image path.
 *
 * @type {string}
 * @private
 */
MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_EXTENSION_ = 'png';


/**
 * Extends a objects prototype by anothers.
 *
 * @param {Object} obj1 The object to be extended.
 * @param {Object} obj2 The object to extend with.
 * @return {Object} The new extended object.
 * @ignore
 */
MarkerClusterer.prototype.extend = function(obj1, obj2) {
    return (function(object) {
        for (var property in object.prototype) {
            this.prototype[property] = object.prototype[property];
        }
        return this;
    }).apply(obj1, [obj2]);
};


/**
 * Implementaion of the interface method.
 * @ignore
 */
MarkerClusterer.prototype.onAdd = function() {
    this.setReady_(true);
};

/**
 * Implementaion of the interface method.
 * @ignore
 */
MarkerClusterer.prototype.draw = function() {};

/**
 * Sets up the styles object.
 *
 * @private
 */
MarkerClusterer.prototype.setupStyles_ = function() {
    if (this.styles_.length) {
        return;
    }

    for (var i = 0, size; size = this.sizes[i]; i++) {
        this.styles_.push({
            url: this.imagePath_ + (i + 1) + '.' + this.imageExtension_,
            height: size,
            width: size
        });
    }
};

/**
 *  Fit the map to the bounds of the markers in the clusterer.
 */
MarkerClusterer.prototype.fitMapToMarkers = function() {
    var markers = this.getMarkers();
    var bounds = new google.maps.LatLngBounds();
    for (var i = 0, marker; marker = markers[i]; i++) {
        bounds.extend(marker.getPosition());
    }

    this.map_.fitBounds(bounds);
};


/**
 *  Sets the styles.
 *
 *  @param {Object} styles The style to set.
 */
MarkerClusterer.prototype.setStyles = function(styles) {
    this.styles_ = styles;
};


/**
 *  Gets the styles.
 *
 *  @return {Object} The styles object.
 */
MarkerClusterer.prototype.getStyles = function() {
    return this.styles_;
};


/**
 * Whether zoom on click is set.
 *
 * @return {boolean} True if zoomOnClick_ is set.
 */
MarkerClusterer.prototype.isZoomOnClick = function() {
    return this.zoomOnClick_;
};

/**
 * Whether average center is set.
 *
 * @return {boolean} True if averageCenter_ is set.
 */
MarkerClusterer.prototype.isAverageCenter = function() {
    return this.averageCenter_;
};


/**
 *  Returns the array of markers in the clusterer.
 *
 *  @return {Array.<google.maps.Marker>} The markers.
 */
MarkerClusterer.prototype.getMarkers = function() {
    return this.markers_;
};


/**
 *  Returns the number of markers in the clusterer
 *
 *  @return {Number} The number of markers.
 */
MarkerClusterer.prototype.getTotalMarkers = function() {
    return this.markers_.length;
};


/**
 *  Sets the max zoom for the clusterer.
 *
 *  @param {number} maxZoom The max zoom level.
 */
MarkerClusterer.prototype.setMaxZoom = function(maxZoom) {
    this.maxZoom_ = maxZoom;
};


/**
 *  Gets the max zoom for the clusterer.
 *
 *  @return {number} The max zoom level.
 */
MarkerClusterer.prototype.getMaxZoom = function() {
    return this.maxZoom_;
};


/**
 *  The function for calculating the cluster icon image.
 *
 *  @param {Array.<google.maps.Marker>} markers The markers in the clusterer.
 *  @param {number} numStyles The number of styles available.
 *  @return {Object} A object properties: 'text' (string) and 'index' (number).
 *  @private
 */
MarkerClusterer.prototype.calculator_ = function(markers, numStyles) {
    var index = 0;
    var count = markers.length;
    var dv = count;
    while (dv !== 0) {
        dv = parseInt(dv / 10, 10);
        index++;
    }

    index = Math.min(index, numStyles);
    return {
        text: count,
        index: index
    };
};


/**
 * Set the calculator function.
 *
 * @param {function(Array, number)} calculator The function to set as the
 *     calculator. The function should return a object properties:
 *     'text' (string) and 'index' (number).
 *
 */
MarkerClusterer.prototype.setCalculator = function(calculator) {
    this.calculator_ = calculator;
};


/**
 * Get the calculator function.
 *
 * @return {function(Array, number)} the calculator function.
 */
MarkerClusterer.prototype.getCalculator = function() {
    return this.calculator_;
};


/**
 * Add an array of markers to the clusterer.
 *
 * @param {Array.<google.maps.Marker>} markers The markers to add.
 * @param {boolean=} opt_nodraw Whether to redraw the clusters.
 */
MarkerClusterer.prototype.addMarkers = function(markers, opt_nodraw) {
    for (var i = 0, marker; marker = markers[i]; i++) {
        this.pushMarkerTo_(marker);
    }
    if (!opt_nodraw) {
        this.redraw();
    }
};


/**
 * Pushes a marker to the clusterer.
 *
 * @param {google.maps.Marker} marker The marker to add.
 * @private
 */
MarkerClusterer.prototype.pushMarkerTo_ = function(marker) {
    marker.isAdded = false;
    if (marker['draggable']) {
        // If the marker is draggable add a listener so we update the clusters on
        // the drag end.
        var that = this;
        google.maps.event.addListener(marker, 'dragend', function() {
            marker.isAdded = false;
            that.repaint();
        });
    }
    this.markers_.push(marker);
};


/**
 * Adds a marker to the clusterer and redraws if needed.
 *
 * @param {google.maps.Marker} marker The marker to add.
 * @param {boolean=} opt_nodraw Whether to redraw the clusters.
 */
MarkerClusterer.prototype.addMarker = function(marker, opt_nodraw) {
    this.pushMarkerTo_(marker);
    if (!opt_nodraw) {
        this.redraw();
    }
};


/**
 * Removes a marker and returns true if removed, false if not
 *
 * @param {google.maps.Marker} marker The marker to remove
 * @return {boolean} Whether the marker was removed or not
 * @private
 */
MarkerClusterer.prototype.removeMarker_ = function(marker) {
    var index = -1;
    if (this.markers_.indexOf) {
        index = this.markers_.indexOf(marker);
    } else {
        for (var i = 0, m; m = this.markers_[i]; i++) {
            if (m == marker) {
                index = i;
                break;
            }
        }
    }

    if (index == -1) {
        // Marker is not in our list of markers.
        return false;
    }

    marker.setMap(null);

    this.markers_.splice(index, 1);

    return true;
};


/**
 * Remove a marker from the cluster.
 *
 * @param {google.maps.Marker} marker The marker to remove.
 * @param {boolean=} opt_nodraw Optional boolean to force no redraw.
 * @return {boolean} True if the marker was removed.
 */
MarkerClusterer.prototype.removeMarker = function(marker, opt_nodraw) {
    var removed = this.removeMarker_(marker);

    if (!opt_nodraw && removed) {
        this.resetViewport();
        this.redraw();
        return true;
    } else {
        return false;
    }
};


/**
 * Removes an array of markers from the cluster.
 *
 * @param {Array.<google.maps.Marker>} markers The markers to remove.
 * @param {boolean=} opt_nodraw Optional boolean to force no redraw.
 */
MarkerClusterer.prototype.removeMarkers = function(markers, opt_nodraw) {
    var removed = false;

    for (var i = 0, marker; marker = markers[i]; i++) {
        var r = this.removeMarker_(marker);
        removed = removed || r;
    }

    if (!opt_nodraw && removed) {
        this.resetViewport();
        this.redraw();
        return true;
    }
};


/**
 * Sets the clusterer's ready state.
 *
 * @param {boolean} ready The state.
 * @private
 */
MarkerClusterer.prototype.setReady_ = function(ready) {
    if (!this.ready_) {
        this.ready_ = ready;
        this.createClusters_();
    }
};


/**
 * Returns the number of clusters in the clusterer.
 *
 * @return {number} The number of clusters.
 */
MarkerClusterer.prototype.getTotalClusters = function() {
    return this.clusters_.length;
};


/**
 * Returns the google map that the clusterer is associated with.
 *
 * @return {google.maps.Map} The map.
 */
MarkerClusterer.prototype.getMap = function() {
    return this.map_;
};


/**
 * Sets the google map that the clusterer is associated with.
 *
 * @param {google.maps.Map} map The map.
 */
MarkerClusterer.prototype.setMap = function(map) {
    this.map_ = map;
};


/**
 * Returns the size of the grid.
 *
 * @return {number} The grid size.
 */
MarkerClusterer.prototype.getGridSize = function() {
    return this.gridSize_;
};


/**
 * Sets the size of the grid.
 *
 * @param {number} size The grid size.
 */
MarkerClusterer.prototype.setGridSize = function(size) {
    this.gridSize_ = size;
};


/**
 * Returns the min cluster size.
 *
 * @return {number} The grid size.
 */
MarkerClusterer.prototype.getMinClusterSize = function() {
    return this.minClusterSize_;
};

/**
 * Sets the min cluster size.
 *
 * @param {number} size The grid size.
 */
MarkerClusterer.prototype.setMinClusterSize = function(size) {
    this.minClusterSize_ = size;
};


/**
 * Extends a bounds object by the grid size.
 *
 * @param {google.maps.LatLngBounds} bounds The bounds to extend.
 * @return {google.maps.LatLngBounds} The extended bounds.
 */
MarkerClusterer.prototype.getExtendedBounds = function(bounds) {
    var projection = this.getProjection();

    // Turn the bounds into latlng.
    var tr = new google.maps.LatLng(bounds.getNorthEast().lat(),
        bounds.getNorthEast().lng());
    var bl = new google.maps.LatLng(bounds.getSouthWest().lat(),
        bounds.getSouthWest().lng());

    // Convert the points to pixels and the extend out by the grid size.
    var trPix = projection.fromLatLngToDivPixel(tr);
    trPix.x += this.gridSize_;
    trPix.y -= this.gridSize_;

    var blPix = projection.fromLatLngToDivPixel(bl);
    blPix.x -= this.gridSize_;
    blPix.y += this.gridSize_;

    // Convert the pixel points back to LatLng
    var ne = projection.fromDivPixelToLatLng(trPix);
    var sw = projection.fromDivPixelToLatLng(blPix);

    // Extend the bounds to contain the new bounds.
    bounds.extend(ne);
    bounds.extend(sw);

    return bounds;
};


/**
 * Determins if a marker is contained in a bounds.
 *
 * @param {google.maps.Marker} marker The marker to check.
 * @param {google.maps.LatLngBounds} bounds The bounds to check against.
 * @return {boolean} True if the marker is in the bounds.
 * @private
 */
MarkerClusterer.prototype.isMarkerInBounds_ = function(marker, bounds) {
    return bounds.contains(marker.getPosition());
};


/**
 * Clears all clusters and markers from the clusterer.
 */
MarkerClusterer.prototype.clearMarkers = function() {
    this.resetViewport(true);

    // Set the markers a empty array.
    this.markers_ = [];
};


/**
 * Clears all existing clusters and recreates them.
 * @param {boolean} opt_hide To also hide the marker.
 */
MarkerClusterer.prototype.resetViewport = function(opt_hide) {
    // Remove all the clusters
    for (var i = 0, cluster; cluster = this.clusters_[i]; i++) {
        cluster.remove();
    }

    // Reset the markers to not be added and to be invisible.
    for (var i = 0, marker; marker = this.markers_[i]; i++) {
        marker.isAdded = false;
        if (opt_hide) {
            marker.setMap(null);
        }
    }

    this.clusters_ = [];
};

/**
 *
 */
MarkerClusterer.prototype.repaint = function() {
    var oldClusters = this.clusters_.slice();
    this.clusters_.length = 0;
    this.resetViewport();
    this.redraw();

    // Remove the old clusters.
    // Do it in a timeout so the other clusters have been drawn first.
    window.setTimeout(function() {
        for (var i = 0, cluster; cluster = oldClusters[i]; i++) {
            cluster.remove();
        }
    }, 0);
};


/**
 * Redraws the clusters.
 */
MarkerClusterer.prototype.redraw = function() {
    this.createClusters_();
};


/**
 * Calculates the distance between two latlng locations in km.
 * @see http://www.movable-type.co.uk/scripts/latlong.html
 *
 * @param {google.maps.LatLng} p1 The first lat lng point.
 * @param {google.maps.LatLng} p2 The second lat lng point.
 * @return {number} The distance between the two points in km.
 * @private
 */
MarkerClusterer.prototype.distanceBetweenPoints_ = function(p1, p2) {
    if (!p1 || !p2) {
        return 0;
    }

    var R = 6371; // Radius of the Earth in km
    var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;
    var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;
    var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) *
        Math.sin(dLon / 2) * Math.sin(dLon / 2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    var d = R * c;
    return d;
};


/**
 * Add a marker to a cluster, or creates a new cluster.
 *
 * @param {google.maps.Marker} marker The marker to add.
 * @private
 */
MarkerClusterer.prototype.addToClosestCluster_ = function(marker) {
    var distance = 40000; // Some large number
    var clusterToAddTo = null;
    var pos = marker.getPosition();
    for (var i = 0, cluster; cluster = this.clusters_[i]; i++) {
        var center = cluster.getCenter();
        if (center) {
            var d = this.distanceBetweenPoints_(center, marker.getPosition());
            if (d < distance) {
                distance = d;
                clusterToAddTo = cluster;
            }
        }
    }

    if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) {
        clusterToAddTo.addMarker(marker);
    } else {
        var cluster = new Cluster(this);
        cluster.addMarker(marker);
        this.clusters_.push(cluster);
    }
};


/**
 * Creates the clusters.
 *
 * @private
 */
MarkerClusterer.prototype.createClusters_ = function() {
    if (!this.ready_) {
        return;
    }

    // Get our current map view bounds.
    // Create a new bounds object so we don't affect the map.
    var mapBounds = new google.maps.LatLngBounds(this.map_.getBounds().getSouthWest(),
        this.map_.getBounds().getNorthEast());
    var bounds = this.getExtendedBounds(mapBounds);

    for (var i = 0, marker; marker = this.markers_[i]; i++) {
        if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) {
            this.addToClosestCluster_(marker);
        }
    }
};


/**
 * A cluster that contains markers.
 *
 * @param {MarkerClusterer} markerClusterer The markerclusterer that this
 *     cluster is associated with.
 * @constructor
 * @ignore
 */
function Cluster(markerClusterer) {
    this.markerClusterer_ = markerClusterer;
    this.map_ = markerClusterer.getMap();
    this.gridSize_ = markerClusterer.getGridSize();
    this.minClusterSize_ = markerClusterer.getMinClusterSize();
    this.averageCenter_ = markerClusterer.isAverageCenter();
    this.center_ = null;
    this.markers_ = [];
    this.bounds_ = null;
    this.clusterIcon_ = new ClusterIcon(this, markerClusterer.getStyles(),
        markerClusterer.getGridSize());
}

/**
 * Determins if a marker is already added to the cluster.
 *
 * @param {google.maps.Marker} marker The marker to check.
 * @return {boolean} True if the marker is already added.
 */
Cluster.prototype.isMarkerAlreadyAdded = function(marker) {
    if (this.markers_.indexOf) {
        return this.markers_.indexOf(marker) != -1;
    } else {
        for (var i = 0, m; m = this.markers_[i]; i++) {
            if (m == marker) {
                return true;
            }
        }
    }
    return false;
};


/**
 * Add a marker the cluster.
 *
 * @param {google.maps.Marker} marker The marker to add.
 * @return {boolean} True if the marker was added.
 */
Cluster.prototype.addMarker = function(marker) {
    if (this.isMarkerAlreadyAdded(marker)) {
        return false;
    }

    if (!this.center_) {
        this.center_ = marker.getPosition();
        this.calculateBounds_();
    } else {
        if (this.averageCenter_) {
            var l = this.markers_.length + 1;
            var lat = (this.center_.lat() * (l-1) + marker.getPosition().lat()) / l;
            var lng = (this.center_.lng() * (l-1) + marker.getPosition().lng()) / l;
            this.center_ = new google.maps.LatLng(lat, lng);
            this.calculateBounds_();
        }
    }

    marker.isAdded = true;
    this.markers_.push(marker);

    var len = this.markers_.length;
    if (len < this.minClusterSize_ && marker.getMap() != this.map_) {
        // Min cluster size not reached so show the marker.
        marker.setMap(this.map_);
    }

    if (len == this.minClusterSize_) {
        // Hide the markers that were showing.
        for (var i = 0; i < len; i++) {
            this.markers_[i].setMap(null);
        }
    }

    if (len >= this.minClusterSize_) {
        marker.setMap(null);
    }

    this.updateIcon();
    return true;
};


/**
 * Returns the marker clusterer that the cluster is associated with.
 *
 * @return {MarkerClusterer} The associated marker clusterer.
 */
Cluster.prototype.getMarkerClusterer = function() {
    return this.markerClusterer_;
};


/**
 * Returns the bounds of the cluster.
 *
 * @return {google.maps.LatLngBounds} the cluster bounds.
 */
Cluster.prototype.getBounds = function() {
    var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
    var markers = this.getMarkers();
    for (var i = 0, marker; marker = markers[i]; i++) {
        bounds.extend(marker.getPosition());
    }
    return bounds;
};


/**
 * Removes the cluster
 */
Cluster.prototype.remove = function() {
    this.clusterIcon_.remove();
    this.markers_.length = 0;
    delete this.markers_;
};


/**
 * Returns the center of the cluster.
 *
 * @return {number} The cluster center.
 */
Cluster.prototype.getSize = function() {
    return this.markers_.length;
};


/**
 * Returns the center of the cluster.
 *
 * @return {Array.<google.maps.Marker>} The cluster center.
 */
Cluster.prototype.getMarkers = function() {
    return this.markers_;
};


/**
 * Returns the center of the cluster.
 *
 * @return {google.maps.LatLng} The cluster center.
 */
Cluster.prototype.getCenter = function() {
    return this.center_;
};


/**
 * Calculated the extended bounds of the cluster with the grid.
 *
 * @private
 */
Cluster.prototype.calculateBounds_ = function() {
    var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
    this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds);
};


/**
 * Determines if a marker lies in the clusters bounds.
 *
 * @param {google.maps.Marker} marker The marker to check.
 * @return {boolean} True if the marker lies in the bounds.
 */
Cluster.prototype.isMarkerInClusterBounds = function(marker) {
    return this.bounds_.contains(marker.getPosition());
};


/**
 * Returns the map that the cluster is associated with.
 *
 * @return {google.maps.Map} The map.
 */
Cluster.prototype.getMap = function() {
    return this.map_;
};


/**
 * Updates the cluster icon
 */
Cluster.prototype.updateIcon = function() {
    var zoom = this.map_.getZoom();
    var mz = this.markerClusterer_.getMaxZoom();

    if (mz && zoom > mz) {
        // The zoom is greater than our max zoom so show all the markers in cluster.
        for (var i = 0, marker; marker = this.markers_[i]; i++) {
            marker.setMap(this.map_);
        }
        return;
    }

    if (this.markers_.length < this.minClusterSize_) {
        // Min cluster size not yet reached.
        this.clusterIcon_.hide();
        return;
    }

    var numStyles = this.markerClusterer_.getStyles().length;
    var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles);
    this.clusterIcon_.setCenter(this.center_);
    this.clusterIcon_.setSums(sums);
    this.clusterIcon_.show();
};


/**
 * A cluster icon
 *
 * @param {Cluster} cluster The cluster to be associated with.
 * @param {Object} styles An object that has style properties:
 *     'url': (string) The image url.
 *     'height': (number) The image height.
 *     'width': (number) The image width.
 *     'anchor': (Array) The anchor position of the label text.
 *     'textColor': (string) The text color.
 *     'textSize': (number) The text size.
 *     'backgroundPosition: (string) The background postition x, y.
 * @param {number=} opt_padding Optional padding to apply to the cluster icon.
 * @constructor
 * @extends google.maps.OverlayView
 * @ignore
 */
function ClusterIcon(cluster, styles, opt_padding) {
    cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView);

    this.styles_ = styles;
    this.padding_ = opt_padding || 0;
    this.cluster_ = cluster;
    this.center_ = null;
    this.map_ = cluster.getMap();
    this.div_ = null;
    this.sums_ = null;
    this.visible_ = false;

    this.setMap(this.map_);
}


/**
 * Triggers the clusterclick event and zoom's if the option is set.
 *
 * @param {google.maps.MouseEvent} event The event to propagate
 */
ClusterIcon.prototype.triggerClusterClick = function(event) {
    var markerClusterer = this.cluster_.getMarkerClusterer();

    // Trigger the clusterclick event.
    google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_, event);

    if (markerClusterer.isZoomOnClick()) {
        // Zoom into the cluster.
        this.map_.fitBounds(this.cluster_.getBounds());
    }
};


/**
 * Adding the cluster icon to the dom.
 * @ignore
 */
ClusterIcon.prototype.onAdd = function() {
    this.div_ = document.createElement('DIV');
    if (this.visible_) {
        var pos = this.getPosFromLatLng_(this.center_);
        this.div_.style.cssText = this.createCss(pos);
        this.div_.innerHTML = this.sums_.text;
    }

    var panes = this.getPanes();
    panes.overlayMouseTarget.appendChild(this.div_);

    var that = this;
    google.maps.event.addDomListener(this.div_, 'click', function(event) {
        that.triggerClusterClick(event);
    });
};


/**
 * Returns the position to place the div dending on the latlng.
 *
 * @param {google.maps.LatLng} latlng The position in latlng.
 * @return {google.maps.Point} The position in pixels.
 * @private
 */
ClusterIcon.prototype.getPosFromLatLng_ = function(latlng) {
    var pos = this.getProjection().fromLatLngToDivPixel(latlng);

    if (typeof this.iconAnchor_ === 'object' && this.iconAnchor_.length === 2) {
        pos.x -= this.iconAnchor_[0];
        pos.y -= this.iconAnchor_[1];
    } else {
        pos.x -= parseInt(this.width_ / 2, 10);
        pos.y -= parseInt(this.height_ / 2, 10);
    }
    return pos;
};


/**
 * Draw the icon.
 * @ignore
 */
ClusterIcon.prototype.draw = function() {
    if (this.visible_) {
        var pos = this.getPosFromLatLng_(this.center_);
        this.div_.style.top = pos.y + 'px';
        this.div_.style.left = pos.x + 'px';
    }
};


/**
 * Hide the icon.
 */
ClusterIcon.prototype.hide = function() {
    if (this.div_) {
        this.div_.style.display = 'none';
    }
    this.visible_ = false;
};


/**
 * Position and show the icon.
 */
ClusterIcon.prototype.show = function() {
    if (this.div_) {
        var pos = this.getPosFromLatLng_(this.center_);
        this.div_.style.cssText = this.createCss(pos);
        this.div_.style.display = '';
    }
    this.visible_ = true;
};


/**
 * Remove the icon from the map
 */
ClusterIcon.prototype.remove = function() {
    this.setMap(null);
};


/**
 * Implementation of the onRemove interface.
 * @ignore
 */
ClusterIcon.prototype.onRemove = function() {
    if (this.div_ && this.div_.parentNode) {
        this.hide();
        this.div_.parentNode.removeChild(this.div_);
        this.div_ = null;
    }
};


/**
 * Set the sums of the icon.
 *
 * @param {Object} sums The sums containing:
 *   'text': (string) The text to display in the icon.
 *   'index': (number) The style index of the icon.
 */
ClusterIcon.prototype.setSums = function(sums) {
    this.sums_ = sums;
    this.text_ = sums.text;
    this.index_ = sums.index;
    if (this.div_) {
        this.div_.innerHTML = sums.text;
    }

    this.useStyle();
};


/**
 * Sets the icon to the the styles.
 */
ClusterIcon.prototype.useStyle = function() {
    var index = Math.max(0, this.sums_.index - 1);
    index = Math.min(this.styles_.length - 1, index);
    var style = this.styles_[index];
    this.url_ = style['url'];
    this.height_ = style['height'];
    this.width_ = style['width'];
    this.textColor_ = style['textColor'];
    this.anchor_ = style['anchor'];
    this.textSize_ = style['textSize'];
    this.backgroundPosition_ = style['backgroundPosition'];
    this.iconAnchor_ = style['iconAnchor'];
};


/**
 * Sets the center of the icon.
 *
 * @param {google.maps.LatLng} center The latlng to set as the center.
 */
ClusterIcon.prototype.setCenter = function(center) {
    this.center_ = center;
};


/**
 * Create the css text based on the position of the icon.
 *
 * @param {google.maps.Point} pos The position.
 * @return {string} The css style text.
 */
ClusterIcon.prototype.createCss = function(pos) {
    var style = [];
    style.push('background-image:url(' + this.url_ + ');');
    var backgroundPosition = this.backgroundPosition_ ? this.backgroundPosition_ : '0 0';
    style.push('background-position:' + backgroundPosition + ';');

    if (typeof this.anchor_ === 'object') {
        if (typeof this.anchor_[0] === 'number' && this.anchor_[0] > 0 &&
            this.anchor_[0] < this.height_) {
            style.push('height:' + (this.height_ - this.anchor_[0]) +
                'px; padding-top:' + this.anchor_[0] + 'px;');
        } else if (typeof this.anchor_[0] === 'number' && this.anchor_[0] < 0 &&
            -this.anchor_[0] < this.height_) {
            style.push('height:' + this.height_ + 'px; line-height:' + (this.height_ + this.anchor_[0]) +
                'px;');
        } else {
            style.push('height:' + this.height_ + 'px; line-height:' + this.height_ +
                'px;');
        }
        if (typeof this.anchor_[1] === 'number' && this.anchor_[1] > 0 &&
            this.anchor_[1] < this.width_) {
            style.push('width:' + (this.width_ - this.anchor_[1]) +
                'px; padding-left:' + this.anchor_[1] + 'px;');
        } else {
            style.push('width:' + this.width_ + 'px; text-align:center;');
        }
    } else {
        style.push('height:' + this.height_ + 'px; line-height:' +
            this.height_ + 'px; width:' + this.width_ + 'px; text-align:center;');
    }

    var txtColor = this.textColor_ ? this.textColor_ : 'black';
    var txtSize = this.textSize_ ? this.textSize_ : 11;

    style.push('cursor:pointer; top:' + pos.y + 'px; left:' +
        pos.x + 'px; color:' + txtColor + '; position:absolute; font-size:' +
        txtSize + 'px; font-family:Arial,sans-serif; font-weight:bold');
    return style.join('');
};


// Export Symbols for Closure
// If you are not going to compile with closure then you can remove the
// code below.
window['MarkerClusterer'] = MarkerClusterer;
MarkerClusterer.prototype['addMarker'] = MarkerClusterer.prototype.addMarker;
MarkerClusterer.prototype['addMarkers'] = MarkerClusterer.prototype.addMarkers;
MarkerClusterer.prototype['clearMarkers'] =
    MarkerClusterer.prototype.clearMarkers;
MarkerClusterer.prototype['fitMapToMarkers'] =
    MarkerClusterer.prototype.fitMapToMarkers;
MarkerClusterer.prototype['getCalculator'] =
    MarkerClusterer.prototype.getCalculator;
MarkerClusterer.prototype['getGridSize'] =
    MarkerClusterer.prototype.getGridSize;
MarkerClusterer.prototype['getExtendedBounds'] =
    MarkerClusterer.prototype.getExtendedBounds;
MarkerClusterer.prototype['getMap'] = MarkerClusterer.prototype.getMap;
MarkerClusterer.prototype['getMarkers'] = MarkerClusterer.prototype.getMarkers;
MarkerClusterer.prototype['getMaxZoom'] = MarkerClusterer.prototype.getMaxZoom;
MarkerClusterer.prototype['getStyles'] = MarkerClusterer.prototype.getStyles;
MarkerClusterer.prototype['getTotalClusters'] =
    MarkerClusterer.prototype.getTotalClusters;
MarkerClusterer.prototype['getTotalMarkers'] =
    MarkerClusterer.prototype.getTotalMarkers;
MarkerClusterer.prototype['redraw'] = MarkerClusterer.prototype.redraw;
MarkerClusterer.prototype['removeMarker'] =
    MarkerClusterer.prototype.removeMarker;
MarkerClusterer.prototype['removeMarkers'] =
    MarkerClusterer.prototype.removeMarkers;
MarkerClusterer.prototype['resetViewport'] =
    MarkerClusterer.prototype.resetViewport;
MarkerClusterer.prototype['repaint'] =
    MarkerClusterer.prototype.repaint;
MarkerClusterer.prototype['setCalculator'] =
    MarkerClusterer.prototype.setCalculator;
MarkerClusterer.prototype['setGridSize'] =
    MarkerClusterer.prototype.setGridSize;
MarkerClusterer.prototype['setMaxZoom'] =
    MarkerClusterer.prototype.setMaxZoom;
MarkerClusterer.prototype['onAdd'] = MarkerClusterer.prototype.onAdd;
MarkerClusterer.prototype['draw'] = MarkerClusterer.prototype.draw;

Cluster.prototype['getCenter'] = Cluster.prototype.getCenter;
Cluster.prototype['getSize'] = Cluster.prototype.getSize;
Cluster.prototype['getMarkers'] = Cluster.prototype.getMarkers;

ClusterIcon.prototype['onAdd'] = ClusterIcon.prototype.onAdd;
ClusterIcon.prototype['draw'] = ClusterIcon.prototype.draw;
ClusterIcon.prototype['onRemove'] = ClusterIcon.prototype.onRemove;
!function(e){"use strict";var t={i18n:{ru:{months:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],dayOfWeek:["Вск","Пн","Вт","Ср","Чт","Пт","Сб"]},en:{months:["January","February","March","April","May","June","July","August","September","October","November","December"],dayOfWeek:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]},de:{months:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],dayOfWeek:["So","Mo","Di","Mi","Do","Fr","Sa"]},nl:{months:["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december"],dayOfWeek:["zo","ma","di","wo","do","vr","za"]},tr:{months:["Ocak","Şubat","Mart","Nisan","Mayıs","Haziran","Temmuz","Ağustos","Eylül","Ekim","Kasım","Aralık"],dayOfWeek:["Paz","Pts","Sal","Çar","Per","Cum","Cts"]},fr:{months:["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"],dayOfWeek:["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"]},es:{months:["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"],dayOfWeek:["Dom","Lun","Mar","Mié","Jue","Vie","Sáb"]},th:{months:["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม"],dayOfWeek:["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."]},pl:{months:["styczeń","luty","marzec","kwiecień","maj","czerwiec","lipiec","sierpień","wrzesień","październik","listopad","grudzień"],dayOfWeek:["nd","pn","wt","śr","cz","pt","sb"]},pt:{months:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],dayOfWeek:["Dom","Seg","Ter","Qua","Qui","Sex","Sab"]},ch:{months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],dayOfWeek:["日","一","二","三","四","五","六"]},se:{months:["Januari","Februari","Mars","April","Maj","Juni","Juli","Augusti","September","Oktober","November","December"],dayOfWeek:["Sön","Mån","Tis","Ons","Tor","Fre","Lör"]},kr:{months:["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"],dayOfWeek:["일","월","화","수","목","금","토"]},it:{months:["Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"],dayOfWeek:["Dom","Lun","Mar","Mer","Gio","Ven","Sab"]},da:{months:["January","Februar","Marts","April","Maj","Juni","July","August","September","Oktober","November","December"],dayOfWeek:["Søn","Man","Tir","ons","Tor","Fre","lør"]},ja:{months:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],dayOfWeek:["日","月","火","水","木","金","土"]},vi:{months:["Tháng 1","Tháng 2","Tháng 3","Tháng 4","Tháng 5","Tháng 6","Tháng 7","Tháng 8","Tháng 9","Tháng 10","Tháng 11","Tháng 12"],dayOfWeek:["CN","T2","T3","T4","T5","T6","T7"]}},value:"",lang:"en",format:"Y/m/d H:i",formatTime:"H:i",formatDate:"Y/m/d",startDate:!1,step:60,closeOnDateSelect:!1,closeOnWithoutClick:!0,timepicker:!0,datepicker:!0,minDate:!1,maxDate:!1,minTime:!1,maxTime:!1,allowTimes:[],opened:!1,initTime:!0,inline:!1,onSelectDate:function(){},onSelectTime:function(){},onChangeMonth:function(){},onChangeDateTime:function(){},onShow:function(){},onClose:function(){},onGenerate:function(){},withoutCopyright:!0,inverseButton:!1,hours12:!1,next:"xdsoft_next",prev:"xdsoft_prev",dayOfWeekStart:0,timeHeightInTimePicker:25,timepickerScrollbar:!0,todayButton:!0,defaultSelect:!0,scrollMonth:!0,scrollTime:!0,scrollInput:!0,lazyInit:!1,mask:!1,validateOnBlur:!0,allowBlank:!0,yearStart:1950,yearEnd:2050,style:"",id:"",roundTime:"round",className:"",weekends:[],yearOffset:0};Array.prototype.indexOf||(Array.prototype.indexOf=function(e,t){for(var n=t||0,a=this.length;n<a;n++)if(this[n]===e)return n;return-1}),e.fn.xdsoftScroller=function(t){return this.each(function(){var n=e(this);if(!e(this).hasClass("xdsoft_scroller_box")){var a=function(e){var t={x:0,y:0};if("touchstart"==e.type||"touchmove"==e.type||"touchend"==e.type||"touchcancel"==e.type){var n=e.originalEvent.touches[0]||e.originalEvent.changedTouches[0];t.x=n.pageX,t.y=n.pageY}else"mousedown"!=e.type&&"mouseup"!=e.type&&"mousemove"!=e.type&&"mouseover"!=e.type&&"mouseout"!=e.type&&"mouseenter"!=e.type&&"mouseleave"!=e.type||(t.x=e.pageX,t.y=e.pageY);return t},r=0,o=n.children().eq(0),s=n[0].clientHeight,i=o[0].offsetHeight,d=e('<div class="xdsoft_scrollbar"></div>'),u=e('<div class="xdsoft_scroller"></div>'),c=100,l=!1;d.append(u),n.addClass("xdsoft_scroller_box").append(d),u.on("mousedown.xdsoft_scroller",function(a){s||n.trigger("resize_scroll.xdsoft_scroller",[t]);var o=a.pageY,i=parseInt(u.css("margin-top")),l=d[0].offsetHeight;e(document.body).addClass("xdsoft_noselect"),e([document.body,window]).on("mouseup.xdsoft_scroller",function f(){e([document.body,window]).off("mouseup.xdsoft_scroller",f).off("mousemove.xdsoft_scroller",r).removeClass("xdsoft_noselect")}),e(document.body).on("mousemove.xdsoft_scroller",r=function(e){var t=e.pageY-o+i;t<0&&(t=0),t+u[0].offsetHeight>l&&(t=l-u[0].offsetHeight),n.trigger("scroll_element.xdsoft_scroller",[c?t/c:0])})}),n.on("scroll_element.xdsoft_scroller",function(e,t){s||n.trigger("resize_scroll.xdsoft_scroller",[t,!0]),t=t>1?1:t<0||isNaN(t)?0:t,u.css("margin-top",c*t),o.css("marginTop",-parseInt((i-s)*t))}).on("resize_scroll.xdsoft_scroller",function(e,t,a){s=n[0].clientHeight,i=o[0].offsetHeight;var r=s/i,l=r*d[0].offsetHeight;r>1?u.hide():(u.show(),u.css("height",parseInt(l>10?l:10)),c=d[0].offsetHeight-u[0].offsetHeight,a!==!0&&n.trigger("scroll_element.xdsoft_scroller",[t?t:Math.abs(parseInt(o.css("marginTop")))/(i-s)]))}),n.mousewheel&&n.mousewheel(function(e,t,a,r){var d=Math.abs(parseInt(o.css("marginTop")));return n.trigger("scroll_element.xdsoft_scroller",[(d-20*t)/(i-s)]),e.stopPropagation(),!1}),n.on("touchstart",function(e){l=a(e)}),n.on("touchmove",function(e){if(l){var t=a(e),r=Math.abs(parseInt(o.css("marginTop")));n.trigger("scroll_element.xdsoft_scroller",[(r-(t.y-l.y))/(i-s)]),e.stopPropagation(),e.preventDefault()}}),n.on("touchend touchcancel",function(e){l=!1})}n.trigger("resize_scroll.xdsoft_scroller",[t])})},e.fn.datetimepicker=function(n){var a=48,r=57,o=96,s=105,i=17,d=46,u=13,c=27,l=8,f=37,m=38,h=39,g=40,p=9,x=116,v=65,y=67,D=86,T=90,w=89,b=!1,_=e.isPlainObject(n)||!n?e.extend(!0,{},t,n):e.extend({},t),M=0,k=function(e){e.on("open.xdsoft focusin.xdsoft mousedown.xdsoft",function t(n){e.is(":disabled")||e.is(":hidden")||!e.is(":visible")||e.data("xdsoft_datetimepicker")||(clearTimeout(M),M=setTimeout(function(){e.data("xdsoft_datetimepicker")||S(e),e.off("open.xdsoft focusin.xdsoft mousedown.xdsoft",t).trigger("open.xdsoft")},100))})},S=function(t){function n(){var e=_.value?_.value:t&&t.val&&t.val()?t.val():"";return e&&W.isValidDate(e=Date.parseDate(e,_.format))?M.data("changed",!0):e="",e||_.startDate===!1||(e=W.strToDateTime(_.startDate)),e?e:0}var M=e("<div "+(_.id?'id="'+_.id+'"':"")+" "+(_.style?'style="'+_.style+'"':"")+' class="xdsoft_datetimepicker xdsoft_noselect '+_.className+'"></div>'),k=e('<div class="xdsoft_copyright"><a target="_blank" href="http://xdsoft.net/jqplugins/datetimepicker/">xdsoft.net</a></div>'),S=e('<div class="xdsoft_datepicker active"></div>'),O=e('<div class="xdsoft_mounthpicker"><button type="button" class="xdsoft_prev"></button><button type="button" class="xdsoft_today_button"></button><div class="xdsoft_label xdsoft_month"><span></span></div><div class="xdsoft_label xdsoft_year"><span></span></div><button type="button" class="xdsoft_next"></button></div>'),F=e('<div class="xdsoft_calendar"></div>'),I=e('<div class="xdsoft_timepicker active"><button type="button" class="xdsoft_prev"></button><div class="xdsoft_time_box"></div><button type="button" class="xdsoft_next"></button></div>'),C=I.find(".xdsoft_time_box").eq(0),H=e('<div class="xdsoft_time_variant"></div>'),Y=e('<div class="xdsoft_scrollbar"></div>'),P=(e('<div class="xdsoft_scroller"></div>'),e('<div class="xdsoft_select xdsoft_monthselect"><div></div></div>')),A=e('<div class="xdsoft_select xdsoft_yearselect"><div></div></div>');O.find(".xdsoft_month span").after(P),O.find(".xdsoft_year span").after(A),O.find(".xdsoft_month,.xdsoft_year").on("mousedown.xdsoft",function(t){O.find(".xdsoft_select").hide();var n=e(this).find(".xdsoft_select").eq(0),a=0,r=0;W.currentTime&&(a=W.currentTime[e(this).hasClass("xdsoft_month")?"getMonth":"getFullYear"]()),n.show();for(var o=n.find("div.xdsoft_option"),s=0;s<o.length&&o.eq(s).data("value")!=a;s++)r+=o[0].offsetHeight;return n.xdsoftScroller(r/(n.children()[0].offsetHeight-n[0].clientHeight)),t.stopPropagation(),!1}),O.find(".xdsoft_select").xdsoftScroller().on("mousedown.xdsoft",function(e){e.stopPropagation(),e.preventDefault()}).on("mousedown.xdsoft",".xdsoft_option",function(t){W&&W.currentTime&&W.currentTime[e(this).parent().parent().hasClass("xdsoft_monthselect")?"setMonth":"setFullYear"](e(this).data("value")),e(this).parent().parent().hide(),M.trigger("xchange.xdsoft"),_.onChangeMonth&&_.onChangeMonth.call&&_.onChangeMonth.call(M,W.currentTime,M.data("input"))}),M.setOptions=function(n){if(_=e.extend(!0,{},_,n),n.allowTimes&&e.isArray(n.allowTimes)&&n.allowTimes.length&&(_.allowTimes=e.extend(!0,[],n.allowTimes)),n.weekends&&e.isArray(n.weekends)&&n.weekends.length&&(_.weekends=e.extend(!0,[],n.weekends)),!_.open&&!_.opened||_.inline||t.trigger("open.xdsoft"),_.inline&&(M.addClass("xdsoft_inline"),t.after(M).hide(),M.trigger("afterOpen.xdsoft")),_.inverseButton&&(_.next="xdsoft_prev",_.prev="xdsoft_next"),_.datepicker?S.addClass("active"):S.removeClass("active"),_.timepicker?I.addClass("active"):I.removeClass("active"),_.value&&(t&&t.val&&t.val(_.value),W.setCurrentTime(_.value)),isNaN(_.dayOfWeekStart)||parseInt(_.dayOfWeekStart)<0||parseInt(_.dayOfWeekStart)>6?_.dayOfWeekStart=0:_.dayOfWeekStart=parseInt(_.dayOfWeekStart),_.timepickerScrollbar||Y.hide(),_.minDate&&/^-(.*)$/.test(_.minDate)&&(_.minDate=W.strToDateTime(_.minDate).dateFormat(_.formatDate)),_.maxDate&&/^\+(.*)$/.test(_.maxDate)&&(_.maxDate=W.strToDateTime(_.maxDate).dateFormat(_.formatDate)),O.find(".xdsoft_today_button").css("visibility",_.todayButton?"visible":"hidden"),_.mask){var k=function(e){try{if(document.selection&&document.selection.createRange){var t=document.selection.createRange();return t.getBookmark().charCodeAt(2)-2}if(e.setSelectionRange)return e.selectionStart}catch(n){return 0}},F=function(e,t){var e="string"==typeof e||e instanceof String?document.getElementById(e):e;if(!e)return!1;if(e.createTextRange){var n=e.createTextRange();return n.collapse(!0),n.moveEnd(t),n.moveStart(t),n.select(),!0}return!!e.setSelectionRange&&(e.setSelectionRange(t,t),!0)},C=function(e,t){var n=e.replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g,"\\$1").replace(/_/g,"{digit+}").replace(/([0-9]{1})/g,"{digit$1}").replace(/\{digit([0-9]{1})\}/g,"[0-$1_]{1}").replace(/\{digit[\+]\}/g,"[0-9_]{1}");return RegExp(n).test(t)};switch(t.off("keydown.xdsoft"),!0){case _.mask===!0:_.mask=_.format.replace(/Y/g,"9999").replace(/F/g,"9999").replace(/m/g,"19").replace(/d/g,"39").replace(/H/g,"29").replace(/i/g,"59").replace(/s/g,"59");case"string"==e.type(_.mask):C(_.mask,t.val())||t.val(_.mask.replace(/[0-9]/g,"_")),t.on("keydown.xdsoft",function(n){var M=this.value,S=n.which;switch(!0){case S>=a&&S<=r||S>=o&&S<=s||S==l||S==d:var O=k(this),I=S!=l&&S!=d?String.fromCharCode(o<=S&&S<=s?S-a:S):"_";for(S!=l&&S!=d||!O||(O--,I="_");/[^0-9_]/.test(_.mask.substr(O,1))&&O<_.mask.length&&O>0;)O+=S==l||S==d?-1:1;if(M=M.substr(0,O)+I+M.substr(O+1),""==e.trim(M))M=_.mask.replace(/[0-9]/g,"_");else if(O==_.mask.length)break;for(O+=S==l||S==d?0:1;/[^0-9_]/.test(_.mask.substr(O,1))&&O<_.mask.length&&O>0;)O+=S==l||S==d?-1:1;C(_.mask,M)?(this.value=M,F(this,O)):""==e.trim(M)?this.value=_.mask.replace(/[0-9]/g,"_"):t.trigger("error_input.xdsoft");break;case!!~[v,y,D,T,w].indexOf(S)&&b:case!!~[c,m,g,f,h,x,i,p,u].indexOf(S):return!0}return n.preventDefault(),!1})}}_.validateOnBlur&&t.off("blur.xdsoft").on("blur.xdsoft",function(){_.allowBlank&&!e.trim(e(this).val()).length?(e(this).val(null),M.data("xdsoft_datetime").empty()):Date.parseDate(e(this).val(),_.format)?M.data("xdsoft_datetime").setCurrentTime(e(this).val()):(e(this).val(W.now().dateFormat(_.format)),M.data("xdsoft_datetime").setCurrentTime(e(this).val())),M.trigger("changedatetime.xdsoft")}),_.dayOfWeekStartPrev=0==_.dayOfWeekStart?6:_.dayOfWeekStart-1,M.trigger("xchange.xdsoft")},M.data("options",_).on("mousedown.xdsoft",function(e){return e.stopPropagation(),e.preventDefault(),A.hide(),P.hide(),!1});var N=I.find(".xdsoft_time_box");N.append(H),N.xdsoftScroller(),M.on("afterOpen.xdsoft",function(){N.xdsoftScroller()}),M.append(S).append(I),_.withoutCopyright!==!0&&M.append(k),S.append(O).append(F),e("body").append(M);var W=new function(){var e=this;e.now=function(){var e=new Date;return _.yearOffset&&e.setFullYear(e.getFullYear()+_.yearOffset),e},e.currentTime=this.now(),e.isValidDate=function(e){return"[object Date]"===Object.prototype.toString.call(e)&&!isNaN(e.getTime())},e.setCurrentTime=function(t){e.currentTime="string"==typeof t?e.strToDateTime(t):e.isValidDate(t)?t:e.now(),M.trigger("xchange.xdsoft")},e.empty=function(){e.currentTime=null},e.getCurrentTime=function(t){return e.currentTime},e.nextMonth=function(){var t=e.currentTime.getMonth()+1;return 12==t&&(e.currentTime.setFullYear(e.currentTime.getFullYear()+1),t=0),e.currentTime.setDate(Math.min(Date.daysInMonth[t],e.currentTime.getDate())),e.currentTime.setMonth(t),_.onChangeMonth&&_.onChangeMonth.call&&_.onChangeMonth.call(M,W.currentTime,M.data("input")),M.trigger("xchange.xdsoft"),t},e.prevMonth=function(){var t=e.currentTime.getMonth()-1;return t==-1&&(e.currentTime.setFullYear(e.currentTime.getFullYear()-1),t=11),e.currentTime.setDate(Math.min(Date.daysInMonth[t],e.currentTime.getDate())),e.currentTime.setMonth(t),_.onChangeMonth&&_.onChangeMonth.call&&_.onChangeMonth.call(M,W.currentTime,M.data("input")),M.trigger("xchange.xdsoft"),t},e.strToDateTime=function(t){var n,a,r=[];return(r=/^(\+|\-)(.*)$/.exec(t))&&(r[2]=Date.parseDate(r[2],_.formatDate))?(n=r[2].getTime()-1*r[2].getTimezoneOffset()*6e4,a=new Date(W.now().getTime()+parseInt(r[1]+"1")*n)):a=t?Date.parseDate(t,_.format):e.now(),e.isValidDate(a)||(a=e.now()),a},e.strtodate=function(t){var n=t?Date.parseDate(t,_.formatDate):e.now();return e.isValidDate(n)||(n=e.now()),n},e.strtotime=function(t){var n=t?Date.parseDate(t,_.formatTime):e.now();return e.isValidDate(n)||(n=e.now()),n},e.str=function(){return e.currentTime.dateFormat(_.format)}};O.find(".xdsoft_today_button").on("mousedown.xdsoft",function(){M.data("changed",!0),W.setCurrentTime(0),M.trigger("afterOpen.xdsoft")}).on("dblclick.xdsoft",function(){t.val(W.str()),M.trigger("close.xdsoft")}),O.find(".xdsoft_prev,.xdsoft_next").on("mousedown.xdsoft",function(){var t=e(this),n=0,a=!1;!function r(e){W.currentTime.getMonth();t.hasClass(_.next)?W.nextMonth():t.hasClass(_.prev)&&W.prevMonth(),!a&&(n=setTimeout(r,e?e:100))}(500),e([document.body,window]).on("mouseup.xdsoft",function o(){clearTimeout(n),a=!0,e([document.body,window]).off("mouseup.xdsoft",o)})}),I.find(".xdsoft_prev,.xdsoft_next").on("mousedown.xdsoft",function(){var t=e(this),n=0,a=!1,r=110;!function o(e){var s=C[0].clientHeight,i=H[0].offsetHeight,d=Math.abs(parseInt(H.css("marginTop")));t.hasClass(_.next)&&i-s-_.timeHeightInTimePicker>=d?H.css("marginTop","-"+(d+_.timeHeightInTimePicker)+"px"):t.hasClass(_.prev)&&d-_.timeHeightInTimePicker>=0&&H.css("marginTop","-"+(d-_.timeHeightInTimePicker)+"px"),C.trigger("scroll_element.xdsoft_scroller",[Math.abs(parseInt(H.css("marginTop"))/(i-s))]),r=r>10?10:r-10,!a&&(n=setTimeout(o,e?e:r))}(500),e([document.body,window]).on("mouseup.xdsoft",function s(){clearTimeout(n),a=!0,e([document.body,window]).off("mouseup.xdsoft",s)})});var z=0;M.on("xchange.xdsoft",function(t){clearTimeout(z),z=setTimeout(function(){for(var t="",n=new Date(W.currentTime.getFullYear(),W.currentTime.getMonth(),1,12,0,0),a=0,r=W.now();n.getDay()!=_.dayOfWeekStart;)n.setDate(n.getDate()-1);t+="<table><thead><tr>";for(var o=0;o<7;o++)t+="<th>"+_.i18n[_.lang].dayOfWeek[o+_.dayOfWeekStart>6?0:o+_.dayOfWeekStart]+"</th>";t+="</tr></thead>",t+="<tbody><tr>";var s=!1,i=!1;_.maxDate!==!1&&(s=W.strtodate(_.maxDate),s=new Date(s.getFullYear(),s.getMonth(),s.getDate(),23,59,59,999)),_.minDate!==!1&&(i=W.strtodate(_.minDate),i=new Date(i.getFullYear(),i.getMonth(),i.getDate()));for(var d,u,c,l=[];a<W.currentTime.getDaysInMonth()||n.getDay()!=_.dayOfWeekStart||W.currentTime.getMonth()==n.getMonth();)l=[],a++,d=n.getDate(),u=n.getFullYear(),c=n.getMonth(),l.push("xdsoft_date"),(s!==!1&&n>s||i!==!1&&n<i)&&l.push("xdsoft_disabled"),W.currentTime.getMonth()!=c&&l.push("xdsoft_other_month"),(_.defaultSelect||M.data("changed"))&&W.currentTime.dateFormat("d.m.Y")==n.dateFormat("d.m.Y")&&l.push("xdsoft_current"),r.dateFormat("d.m.Y")==n.dateFormat("d.m.Y")&&l.push("xdsoft_today"),(0==n.getDay()||6==n.getDay()||~_.weekends.indexOf(n.dateFormat("d.m.Y")))&&l.push("xdsoft_weekend"),_.beforeShowDay&&"function"==typeof _.beforeShowDay&&l.push(_.beforeShowDay(n)),t+='<td data-date="'+d+'" data-month="'+c+'" data-year="'+u+'" class="xdsoft_date xdsoft_day_of_week'+n.getDay()+" "+l.join(" ")+'"><div>'+d+"</div></td>",n.getDay()==_.dayOfWeekStartPrev&&(t+="</tr>"),n.setDate(d+1);t+="</tbody></table>",F.html(t),O.find(".xdsoft_label span").eq(0).text(_.i18n[_.lang].months[W.currentTime.getMonth()]),O.find(".xdsoft_label span").eq(1).text(W.currentTime.getFullYear());var f="",m="",c="",h=function(e,t){var n=W.now();n.setHours(e),e=parseInt(n.getHours()),n.setMinutes(t),t=parseInt(n.getMinutes()),l=[],(_.maxTime!==!1&&W.strtotime(_.maxTime).getTime()<n.getTime()||_.minTime!==!1&&W.strtotime(_.minTime).getTime()>n.getTime())&&l.push("xdsoft_disabled"),(_.initTime||_.defaultSelect||M.data("changed"))&&parseInt(W.currentTime.getHours())==parseInt(e)&&(_.step>59||Math[_.roundTime](W.currentTime.getMinutes()/_.step)*_.step==parseInt(t))&&(_.defaultSelect||M.data("changed")?l.push("xdsoft_current"):_.initTime&&l.push("xdsoft_init_time")),parseInt(r.getHours())==parseInt(e)&&parseInt(r.getMinutes())==parseInt(t)&&l.push("xdsoft_today"),f+='<div class="xdsoft_time '+l.join(" ")+'" data-hour="'+e+'" data-minute="'+t+'">'+n.dateFormat(_.formatTime)+"</div>"};if(_.allowTimes&&e.isArray(_.allowTimes)&&_.allowTimes.length)for(var a=0;a<_.allowTimes.length;a++)m=W.strtotime(_.allowTimes[a]).getHours(),c=W.strtotime(_.allowTimes[a]).getMinutes(),h(m,c);else for(var a=0,o=0;a<(_.hours12?12:24);a++)for(o=0;o<60;o+=_.step)m=(a<10?"0":"")+a,c=(o<10?"0":"")+o,h(m,c);H.html(f);var g="",a=0;for(a=parseInt(_.yearStart,10)+_.yearOffset;a<=parseInt(_.yearEnd,10)+_.yearOffset;a++)g+='<div class="xdsoft_option '+(W.currentTime.getFullYear()==a?"xdsoft_current":"")+'" data-value="'+a+'">'+a+"</div>";for(A.children().eq(0).html(g),a=0,g="";a<=11;a++)g+='<div class="xdsoft_option '+(W.currentTime.getMonth()==a?"xdsoft_current":"")+'" data-value="'+a+'">'+_.i18n[_.lang].months[a]+"</div>";P.children().eq(0).html(g),e(this).trigger("generate.xdsoft")},10),t.stopPropagation()}).on("afterOpen.xdsoft",function(){if(_.timepicker){var e;if(H.find(".xdsoft_current").length?e=".xdsoft_current":H.find(".xdsoft_init_time").length&&(e=".xdsoft_init_time"),e){var t=C[0].clientHeight,n=H[0].offsetHeight,a=H.find(e).index()*_.timeHeightInTimePicker+1;n-t<a&&(a=n-t),H.css("marginTop","-"+parseInt(a)+"px"),C.trigger("scroll_element.xdsoft_scroller",[parseInt(a)/(n-t)])}}});var J=0;F.on("click.xdsoft","td",function(n){n.stopPropagation(),J++;var a=e(this),r=W.currentTime;return!a.hasClass("xdsoft_disabled")&&(r.setDate(a.data("date")),r.setMonth(a.data("month")),r.setFullYear(a.data("year")),M.trigger("select.xdsoft",[r]),t.val(W.str()),(J>1||_.closeOnDateSelect===!0||0===_.closeOnDateSelect&&!_.timepicker)&&!_.inline&&M.trigger("close.xdsoft"),_.onSelectDate&&_.onSelectDate.call&&_.onSelectDate.call(M,W.currentTime,M.data("input")),M.data("changed",!0),M.trigger("xchange.xdsoft"),M.trigger("changedatetime.xdsoft"),void setTimeout(function(){J=0},200))}),H.on("click.xdsoft","div",function(t){t.stopPropagation();var n=e(this),a=W.currentTime;return!n.hasClass("xdsoft_disabled")&&(a.setHours(n.data("hour")),a.setMinutes(n.data("minute")),M.trigger("select.xdsoft",[a]),M.data("input").val(W.str()),!_.inline&&M.trigger("close.xdsoft"),_.onSelectTime&&_.onSelectTime.call&&_.onSelectTime.call(M,W.currentTime,M.data("input")),M.data("changed",!0),M.trigger("xchange.xdsoft"),void M.trigger("changedatetime.xdsoft"))}),M.mousewheel&&S.mousewheel(function(e,t,n,a){return!_.scrollMonth||(t<0?W.nextMonth():W.prevMonth(),!1)}),M.mousewheel&&C.unmousewheel().mousewheel(function(e,t,n,a){if(!_.scrollTime)return!0;var r=C[0].clientHeight,o=H[0].offsetHeight,s=Math.abs(parseInt(H.css("marginTop"))),i=!0;return t<0&&o-r-_.timeHeightInTimePicker>=s?(H.css("marginTop","-"+(s+_.timeHeightInTimePicker)+"px"),i=!1):t>0&&s-_.timeHeightInTimePicker>=0&&(H.css("marginTop","-"+(s-_.timeHeightInTimePicker)+"px"),i=!1),C.trigger("scroll_element.xdsoft_scroller",[Math.abs(parseInt(H.css("marginTop"))/(o-r))]),e.stopPropagation(),i}),M.on("changedatetime.xdsoft",function(){if(_.onChangeDateTime&&_.onChangeDateTime.call){var e=M.data("input");_.onChangeDateTime.call(M,W.currentTime,e),e.trigger("change")}}).on("generate.xdsoft",function(){_.onGenerate&&_.onGenerate.call&&_.onGenerate.call(M,W.currentTime,M.data("input"))});var j=0;t.mousewheel&&t.mousewheel(function(e,n,a,r){return!_.scrollInput||(!_.datepicker&&_.timepicker?(j=H.find(".xdsoft_current").length?H.find(".xdsoft_current").eq(0).index():0,j+n>=0&&j+n<H.children().length&&(j+=n),H.children().eq(j).length&&H.children().eq(j).trigger("mousedown"),!1):_.datepicker&&!_.timepicker?(S.trigger(e,[n,a,r]),t.val&&t.val(W.str()),M.trigger("changedatetime.xdsoft"),!1):void 0)});var L=function(){var t=M.data("input").offset(),n=t.top+M.data("input")[0].offsetHeight-1,a=t.left;n+M[0].offsetHeight>e(window).height()+e(window).scrollTop()&&(n=t.top-M[0].offsetHeight+1),n<0&&(n=0),a+M[0].offsetWidth>e(window).width()&&(a=t.left-M[0].offsetWidth+M.data("input")[0].offsetWidth),M.css({left:a,top:n})};M.on("open.xdsoft",function(){var t=!0;_.onShow&&_.onShow.call&&(t=_.onShow.call(M,W.currentTime,M.data("input"))),t!==!1&&(M.show(),M.trigger("afterOpen.xdsoft"),L(),e(window).off("resize.xdsoft",L).on("resize.xdsoft",L),_.closeOnWithoutClick&&e([document.body,window]).on("mousedown.xdsoft",function n(){M.trigger("close.xdsoft"),e([document.body,window]).off("mousedown.xdsoft",n)}))}).on("close.xdsoft",function(e){var t=!0;_.onClose&&_.onClose.call&&(t=_.onClose.call(M,W.currentTime,M.data("input"))),t===!1||_.opened||_.inline||M.hide(),e.stopPropagation()}).data("input",t);var E=0;M.data("xdsoft_datetime",W),M.setOptions(_),W.setCurrentTime(n()),M.trigger("afterOpen.xdsoft"),t.data("xdsoft_datetimepicker",M).on("open.xdsoft focusin.xdsoft mousedown.xdsoft",function(e){t.is(":disabled")||t.is(":hidden")||!t.is(":visible")||(clearTimeout(E),E=setTimeout(function(){t.is(":disabled")||t.is(":hidden")||!t.is(":visible")||(W.setCurrentTime(n()),M.trigger("open.xdsoft"))},100))}).on("keydown.xdsoft",function(t){var n=(this.value,t.which);switch(!0){case!!~[u].indexOf(n):var a=e("input:visible,textarea:visible");return M.trigger("close.xdsoft"),a.eq(a.index(this)+1).focus(),!1;case!!~[p].indexOf(n):return M.trigger("close.xdsoft"),!0}})},O=function(t){var n=t.data("xdsoft_datetimepicker");n&&(n.data("xdsoft_datetime",null),n.remove(),t.data("xdsoft_datetimepicker",null).off("open.xdsoft focusin.xdsoft focusout.xdsoft mousedown.xdsoft blur.xdsoft keydown.xdsoft"),e(window).off("resize.xdsoft"),e([window,document.body]).off("mousedown.xdsoft"),t.unmousewheel&&t.unmousewheel())};return e(document).off("keydown.xdsoftctrl keyup.xdsoftctrl").on("keydown.xdsoftctrl",function(e){e.keyCode==i&&(b=!0)}).on("keyup.xdsoftctrl",function(e){e.keyCode==i&&(b=!1)}),this.each(function(){var t;if(t=e(this).data("xdsoft_datetimepicker")){if("string"===e.type(n))switch(n){case"show":e(this).select().focus(),t.trigger("open.xdsoft");break;case"hide":t.trigger("close.xdsoft");break;case"destroy":O(e(this));break;case"reset":this.value=this.defaultValue,this.value&&t.data("xdsoft_datetime").isValidDate(Date.parseDate(this.value,_.format))||t.data("changed",!1),t.data("xdsoft_datetime").setCurrentTime(this.value)}else t.setOptions(n);return 0}"string"!==e.type(n)&&(!_.lazyInit||_.open||_.inline?S(e(this)):k(e(this)))})}}(jQuery),Date.parseFunctions={count:0},Date.parseRegexes=[],Date.formatFunctions={count:0},Date.prototype.dateFormat=function(e){if("unixtime"==e)return parseInt(this.getTime()/1e3);null==Date.formatFunctions[e]&&Date.createNewFormat(e);var t=Date.formatFunctions[e];return this[t]()},Date.createNewFormat=function(format){var funcName="format"+Date.formatFunctions.count++;Date.formatFunctions[format]=funcName;for(var code="Date.prototype."+funcName+" = function() {return ",special=!1,ch="",i=0;i<format.length;++i)ch=format.charAt(i),special||"\\"!=ch?special?(special=!1,code+="'"+String.escape(ch)+"' + "):code+=Date.getFormatCode(ch):special=!0;eval(code.substring(0,code.length-3)+";}")},Date.getFormatCode=function(e){switch(e){case"d":return"String.leftPad(this.getDate(), 2, '0') + ";case"D":return"Date.dayNames[this.getDay()].substring(0, 3) + ";case"j":return"this.getDate() + ";case"l":return"Date.dayNames[this.getDay()] + ";case"S":return"this.getSuffix() + ";case"w":return"this.getDay() + ";case"z":return"this.getDayOfYear() + ";case"W":return"this.getWeekOfYear() + ";case"F":return"Date.monthNames[this.getMonth()] + ";case"m":return"String.leftPad(this.getMonth() + 1, 2, '0') + ";case"M":return"Date.monthNames[this.getMonth()].substring(0, 3) + ";case"n":return"(this.getMonth() + 1) + ";case"t":return"this.getDaysInMonth() + ";case"L":return"(this.isLeapYear() ? 1 : 0) + ";case"Y":return"this.getFullYear() + ";case"y":return"('' + this.getFullYear()).substring(2, 4) + ";case"a":return"(this.getHours() < 12 ? 'am' : 'pm') + ";case"A":return"(this.getHours() < 12 ? 'AM' : 'PM') + ";case"g":return"((this.getHours() %12) ? this.getHours() % 12 : 12) + ";case"G":return"this.getHours() + ";case"h":return"String.leftPad((this.getHours() %12) ? this.getHours() % 12 : 12, 2, '0') + ";case"H":return"String.leftPad(this.getHours(), 2, '0') + ";case"i":return"String.leftPad(this.getMinutes(), 2, '0') + ";case"s":return"String.leftPad(this.getSeconds(), 2, '0') + ";case"O":return"this.getGMTOffset() + ";case"T":return"this.getTimezone() + ";case"Z":return"(this.getTimezoneOffset() * -60) + ";default:return"'"+String.escape(e)+"' + "}},Date.parseDate=function(e,t){if("unixtime"==t)return new Date(isNaN(parseInt(e))?0:1e3*parseInt(e));null==Date.parseFunctions[t]&&Date.createParser(t);var n=Date.parseFunctions[t];return Date[n](e)},Date.createParser=function(format){var funcName="parse"+Date.parseFunctions.count++,regexNum=Date.parseRegexes.length,currentGroup=1;Date.parseFunctions[format]=funcName;for(var code="Date."+funcName+" = function(input) {\nvar y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, z = -1;\nvar d = new Date();\ny = d.getFullYear();\nm = d.getMonth();\nd = d.getDate();\nvar results = input.match(Date.parseRegexes["+regexNum+"]);\nif (results && results.length > 0) {",regex="",special=!1,ch="",i=0;i<format.length;++i)ch=format.charAt(i),special||"\\"!=ch?special?(special=!1,regex+=String.escape(ch)):(obj=Date.formatCodeToRegex(ch,currentGroup),currentGroup+=obj.g,regex+=obj.s,obj.g&&obj.c&&(code+=obj.c)):special=!0;code+="if (y > 0 && z > 0){\nvar doyDate = new Date(y,0);\ndoyDate.setDate(z);\nm = doyDate.getMonth();\nd = doyDate.getDate();\n}",code+="if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n{return new Date(y, m, d, h, i, s);}\nelse if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n{return new Date(y, m, d, h, i);}\nelse if (y > 0 && m >= 0 && d > 0 && h >= 0)\n{return new Date(y, m, d, h);}\nelse if (y > 0 && m >= 0 && d > 0)\n{return new Date(y, m, d);}\nelse if (y > 0 && m >= 0)\n{return new Date(y, m);}\nelse if (y > 0)\n{return new Date(y);}\n}return null;}",Date.parseRegexes[regexNum]=new RegExp("^"+regex+"$"),eval(code)},Date.formatCodeToRegex=function(e,t){switch(e){case"D":return{g:0,c:null,s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};case"j":case"d":return{g:1,c:"d = parseInt(results["+t+"], 10);\n",s:"(\\d{1,2})"};case"l":return{g:0,c:null,s:"(?:"+Date.dayNames.join("|")+")"};case"S":return{g:0,c:null,s:"(?:st|nd|rd|th)"};case"w":return{g:0,c:null,s:"\\d"};case"z":return{g:1,c:"z = parseInt(results["+t+"], 10);\n",s:"(\\d{1,3})"};case"W":return{g:0,c:null,s:"(?:\\d{2})"};case"F":return{g:1,c:"m = parseInt(Date.monthNumbers[results["+t+"].substring(0, 3)], 10);\n",s:"("+Date.monthNames.join("|")+")"};case"M":return{g:1,c:"m = parseInt(Date.monthNumbers[results["+t+"]], 10);\n",s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};case"n":case"m":return{g:1,c:"m = parseInt(results["+t+"], 10) - 1;\n",s:"(\\d{1,2})"};case"t":return{g:0,c:null,s:"\\d{1,2}"};case"L":return{g:0,c:null,s:"(?:1|0)"};case"Y":return{g:1,c:"y = parseInt(results["+t+"], 10);\n",s:"(\\d{4})"};case"y":return{g:1,c:"var ty = parseInt(results["+t+"], 10);\ny = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",s:"(\\d{1,2})"};case"a":return{g:1,c:"if (results["+t+"] == 'am') {\nif (h == 12) { h = 0; }\n} else { if (h < 12) { h += 12; }}",s:"(am|pm)"};case"A":return{g:1,c:"if (results["+t+"] == 'AM') {\nif (h == 12) { h = 0; }\n} else { if (h < 12) { h += 12; }}",s:"(AM|PM)"};case"g":case"G":case"h":case"H":return{g:1,c:"h = parseInt(results["+t+"], 10);\n",s:"(\\d{1,2})"};case"i":return{g:1,c:"i = parseInt(results["+t+"], 10);\n",s:"(\\d{2})"};case"s":return{g:1,c:"s = parseInt(results["+t+"], 10);\n",s:"(\\d{2})"};case"O":return{g:0,c:null,s:"[+-]\\d{4}"};case"T":return{g:0,c:null,s:"[A-Z]{3}"};case"Z":return{g:0,c:null,s:"[+-]\\d{1,5}"};default:return{g:0,c:null,s:String.escape(e)}}},Date.prototype.getTimezone=function(){return this.toString().replace(/^.*? ([A-Z]{3}) [0-9]{4}.*$/,"$1").replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/,"$1$2$3")},Date.prototype.getGMTOffset=function(){return(this.getTimezoneOffset()>0?"-":"+")+String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset())/60),2,"0")+String.leftPad(Math.abs(this.getTimezoneOffset())%60,2,"0")},Date.prototype.getDayOfYear=function(){var e=0;Date.daysInMonth[1]=this.isLeapYear()?29:28;for(var t=0;t<this.getMonth();++t)e+=Date.daysInMonth[t];return e+this.getDate()},Date.prototype.getWeekOfYear=function(){var e=this.getDayOfYear()+(4-this.getDay()),t=new Date(this.getFullYear(),0,1),n=7-t.getDay()+4;return String.leftPad(Math.ceil((e-n)/7)+1,2,"0")},Date.prototype.isLeapYear=function(){var e=this.getFullYear();return 0==(3&e)&&(e%100||e%400==0&&e)},Date.prototype.getFirstDayOfMonth=function(){var e=(this.getDay()-(this.getDate()-1))%7;return e<0?e+7:e},Date.prototype.getLastDayOfMonth=function(){var e=(this.getDay()+(Date.daysInMonth[this.getMonth()]-this.getDate()))%7;return e<0?e+7:e},Date.prototype.getDaysInMonth=function(){return Date.daysInMonth[1]=this.isLeapYear()?29:28,Date.daysInMonth[this.getMonth()]},Date.prototype.getSuffix=function(){switch(this.getDate()){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th"}},String.escape=function(e){return e.replace(/('|\\)/g,"\\$1")},String.leftPad=function(e,t,n){var a=new String(e);for(null==n&&(n=" ");a.length<t;)a=n+a;return a},Date.daysInMonth=[31,28,31,30,31,30,31,31,30,31,30,31],Date.monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"],Date.dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],Date.y2kYear=50,Date.monthNumbers={Jan:0,Feb:1,Mar:2,
Apr:3,May:4,Jun:5,Jul:6,Aug:7,Sep:8,Oct:9,Nov:10,Dec:11},Date.patterns={ISO8601LongPattern:"Y-m-d H:i:s",ISO8601ShortPattern:"Y-m-d",ShortDatePattern:"n/j/Y",LongDatePattern:"l, F d, Y",FullDateTimePattern:"l, F d, Y g:i:s A",MonthDayPattern:"F d",ShortTimePattern:"g:i A",LongTimePattern:"g:i:s A",SortableDateTimePattern:"Y-m-d\\TH:i:s",UniversalSortableDateTimePattern:"Y-m-d H:i:sO",YearMonthPattern:"F, Y"},function(e){"function"==typeof define&&define.amd?define(["jquery.flot.min"],e):"object"==typeof exports?module.exports=e:e(jQuery)}(function(e){function t(t){var r,o=t||window.event,s=[].slice.call(arguments,1),i=0,d=0,u=0,c=0,l=0;return t=e.event.fix(o),t.type="mousewheel",o.wheelDelta&&(i=o.wheelDelta),o.detail&&(i=o.detail*-1),o.deltaY&&(u=o.deltaY*-1,i=u),o.deltaX&&(d=o.deltaX,i=d*-1),void 0!==o.wheelDeltaY&&(u=o.wheelDeltaY),void 0!==o.wheelDeltaX&&(d=o.wheelDeltaX*-1),c=Math.abs(i),(!n||c<n)&&(n=c),l=Math.max(Math.abs(u),Math.abs(d)),(!a||l<a)&&(a=l),r=i>0?"floor":"ceil",i=Math[r](i/n),d=Math[r](d/a),u=Math[r](u/a),s.unshift(t,i,d,u),(e.event.dispatch||e.event.handle).apply(this,s)}var n,a,r=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],o="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"];if(e.event.fixHooks)for(var s=r.length;s;)e.event.fixHooks[r[--s]]=e.event.mouseHooks;e.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var e=o.length;e;)this.addEventListener(o[--e],t,!1);else this.onmousewheel=t},teardown:function(){if(this.removeEventListener)for(var e=o.length;e;)this.removeEventListener(o[--e],t,!1);else this.onmousewheel=null}},e.fn.extend({mousewheel:function(e){return e?this.bind("mousewheel",e):this.trigger("mousewheel")},unmousewheel:function(e){return this.unbind("mousewheel",e)}})});
function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,i=Array(e.length);t<e.length;t++)i[t]=e[t];return i}return Array.from(e)}var _slice=Array.prototype.slice;!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):e.parsley=t(e.jQuery)}(this,function(e){"use strict";function t(e,t){return e.parsleyAdaptedCallback||(e.parsleyAdaptedCallback=function(){var i=Array.prototype.slice.call(arguments,0);i.unshift(this),e.apply(t||O,i)}),e.parsleyAdaptedCallback}function i(e){return 0===e.lastIndexOf(D,0)?e.substr(D.length):e}var n=1,r={},s={attr:function(e,t,i){var n,r,s,a=new RegExp("^"+t,"i");if("undefined"==typeof i)i={};else for(n in i)i.hasOwnProperty(n)&&delete i[n];if("undefined"==typeof e||"undefined"==typeof e[0])return i;for(s=e[0].attributes,n=s.length;n--;)r=s[n],r&&r.specified&&a.test(r.name)&&(i[this.camelize(r.name.slice(t.length))]=this.deserializeValue(r.value));return i},checkAttr:function(e,t,i){return e.is("["+t+i+"]")},setAttr:function(e,t,i,n){e[0].setAttribute(this.dasherize(t+i),String(n))},generateID:function(){return""+n++},deserializeValue:function(t){var i;try{return t?"true"==t||"false"!=t&&("null"==t?null:isNaN(i=Number(t))?/^[\[\{]/.test(t)?e.parseJSON(t):t:i):t}catch(n){return t}},camelize:function(e){return e.replace(/-+(.)?/g,function(e,t){return t?t.toUpperCase():""})},dasherize:function(e){return e.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()},warn:function(){var e;window.console&&"function"==typeof window.console.warn&&(e=window.console).warn.apply(e,arguments)},warnOnce:function(e){r[e]||(r[e]=!0,this.warn.apply(this,arguments))},_resetWarnings:function(){r={}},trimString:function(e){return e.replace(/^\s+|\s+$/g,"")},objectCreate:Object.create||function(){var e=function(){};return function(t){if(arguments.length>1)throw Error("Second argument not supported");if("object"!=typeof t)throw TypeError("Argument must be an object");e.prototype=t;var i=new e;return e.prototype=null,i}}()},a=s,o={namespace:"data-parsley-",inputs:"input, textarea, select",excluded:"input[type=button], input[type=submit], input[type=reset], input[type=hidden]",priorityEnabled:!0,multiple:null,group:null,uiEnabled:!0,validationThreshold:3,focus:"first",trigger:!1,errorClass:"parsley-error",successClass:"parsley-success",classHandler:function(e){},errorsContainer:function(e){},errorsWrapper:'<ul class="parsley-errors-list"></ul>',errorTemplate:"<li></li>"},l=function(){};l.prototype={asyncSupport:!0,actualizeOptions:function(){return a.attr(this.$element,this.options.namespace,this.domOptions),this.parent&&this.parent.actualizeOptions&&this.parent.actualizeOptions(),this},_resetOptions:function(e){this.domOptions=a.objectCreate(this.parent.options),this.options=a.objectCreate(this.domOptions);for(var t in e)e.hasOwnProperty(t)&&(this.options[t]=e[t]);this.actualizeOptions()},_listeners:null,on:function(e,t){this._listeners=this._listeners||{};var i=this._listeners[e]=this._listeners[e]||[];return i.push(t),this},subscribe:function(t,i){e.listenTo(this,t.toLowerCase(),i)},off:function(e,t){var i=this._listeners&&this._listeners[e];if(i)if(t)for(var n=i.length;n--;)i[n]===t&&i.splice(n,1);else delete this._listeners[e];return this},unsubscribe:function(t,i){e.unsubscribeTo(this,t.toLowerCase())},trigger:function(e,t,i){t=t||this;var n,r=this._listeners&&this._listeners[e];if(r)for(var s=r.length;s--;)if(n=r[s].call(t,t,i),n===!1)return n;return!this.parent||this.parent.trigger(e,t,i)},reset:function(){if("ParsleyForm"!==this.__class__)return this._trigger("reset");for(var e=0;e<this.fields.length;e++)this.fields[e]._trigger("reset");this._trigger("reset")},destroy:function(){if("ParsleyForm"!==this.__class__)return this.$element.removeData("Parsley"),this.$element.removeData("ParsleyFieldMultiple"),void this._trigger("destroy");for(var e=0;e<this.fields.length;e++)this.fields[e].destroy();this.$element.removeData("Parsley"),this._trigger("destroy")},asyncIsValid:function(e,t){return a.warnOnce("asyncIsValid is deprecated; please use whenValid instead"),this.whenValid({group:e,force:t})},_findRelated:function(){return this.options.multiple?this.parent.$element.find("["+this.options.namespace+'multiple="'+this.options.multiple+'"]'):this.$element}};var u={string:function(e){return e},integer:function(e){if(isNaN(e))throw'Requirement is not an integer: "'+e+'"';return parseInt(e,10)},number:function(e){if(isNaN(e))throw'Requirement is not a number: "'+e+'"';return parseFloat(e)},reference:function(t){var i=e(t);if(0===i.length)throw'No such reference: "'+t+'"';return i},"boolean":function(e){return"false"!==e},object:function(e){return a.deserializeValue(e)},regexp:function(e){var t="";return/^\/.*\/(?:[gimy]*)$/.test(e)?(t=e.replace(/.*\/([gimy]*)$/,"$1"),e=e.replace(new RegExp("^/(.*?)/"+t+"$"),"$1")):e="^"+e+"$",new RegExp(e,t)}},d=function(e,t){var i=e.match(/^\s*\[(.*)\]\s*$/);if(!i)throw'Requirement is not an array: "'+e+'"';var n=i[1].split(",").map(a.trimString);if(n.length!==t)throw"Requirement has "+n.length+" values when "+t+" are needed";return n},h=function(e,t){var i=u[e||"string"];if(!i)throw'Unknown requirement specification: "'+e+'"';return i(t)},p=function(e,t,i){var n=null,r={};for(var s in e)if(s){var a=i(s);"string"==typeof a&&(a=h(e[s],a)),r[s]=a}else n=h(e[s],t);return[n,r]},f=function(t){e.extend(!0,this,t)};f.prototype={validate:function(t,i){if(this.fn)return arguments.length>3&&(i=[].slice.call(arguments,1,-1)),this.fn.call(this,t,i);if(e.isArray(t)){if(!this.validateMultiple)throw"Validator `"+this.name+"` does not handle multiple values";return this.validateMultiple.apply(this,arguments)}if(this.validateNumber)return!isNaN(t)&&(arguments[0]=parseFloat(arguments[0]),this.validateNumber.apply(this,arguments));if(this.validateString)return this.validateString.apply(this,arguments);throw"Validator `"+this.name+"` only handles multiple values"},parseRequirements:function(t,i){if("string"!=typeof t)return e.isArray(t)?t:[t];var n=this.requirementType;if(e.isArray(n)){for(var r=d(t,n.length),s=0;s<r.length;s++)r[s]=h(n[s],r[s]);return r}return e.isPlainObject(n)?p(n,t,i):[h(n,t)]},requirementType:"string",priority:2};var c=function(e,t){this.__class__="ParsleyValidatorRegistry",this.locale="en",this.init(e||{},t||{})},m={email:/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,number:/^-?(\d*\.)?\d+(e[-+]?\d+)?$/i,integer:/^-?\d+$/,digits:/^\d+$/,alphanum:/^\w+$/i,url:new RegExp("^(?:(?:https?|ftp)://)?(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:/\\S*)?$","i")};m.range=m.number;var y=function(e){var t=(""+e).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);return t?Math.max(0,(t[1]?t[1].length:0)-(t[2]?+t[2]:0)):0};c.prototype={init:function(t,i){this.catalog=i,this.validators=e.extend({},this.validators);for(var n in t)this.addValidator(n,t[n].fn,t[n].priority);window.Parsley.trigger("parsley:validator:init")},setLocale:function(e){if("undefined"==typeof this.catalog[e])throw new Error(e+" is not available in the catalog");return this.locale=e,this},addCatalog:function(e,t,i){return"object"==typeof t&&(this.catalog[e]=t),!0===i?this.setLocale(e):this},addMessage:function(e,t,i){return"undefined"==typeof this.catalog[e]&&(this.catalog[e]={}),this.catalog[e][t]=i,this},addMessages:function(e,t){for(var i in t)this.addMessage(e,i,t[i]);return this},addValidator:function(e,t,i){if(this.validators[e])a.warn('Validator "'+e+'" is already defined.');else if(o.hasOwnProperty(e))return void a.warn('"'+e+'" is a restricted keyword and is not a valid validator name.');return this._setValidator.apply(this,arguments)},updateValidator:function(e,t,i){return this.validators[e]?this._setValidator(this,arguments):(a.warn('Validator "'+e+'" is not already defined.'),this.addValidator.apply(this,arguments))},removeValidator:function(e){return this.validators[e]||a.warn('Validator "'+e+'" is not defined.'),delete this.validators[e],this},_setValidator:function(e,t,i){"object"!=typeof t&&(t={fn:t,priority:i}),t.validate||(t=new f(t)),this.validators[e]=t;for(var n in t.messages||{})this.addMessage(n,e,t.messages[n]);return this},getErrorMessage:function(e){var t;if("type"===e.name){var i=this.catalog[this.locale][e.name]||{};t=i[e.requirements]}else t=this.formatMessage(this.catalog[this.locale][e.name],e.requirements);return t||this.catalog[this.locale].defaultMessage||this.catalog.en.defaultMessage},formatMessage:function(e,t){if("object"==typeof t){for(var i in t)e=this.formatMessage(e,t[i]);return e}return"string"==typeof e?e.replace(/%s/i,t):""},validators:{notblank:{validateString:function(e){return/\S/.test(e)},priority:2},required:{validateMultiple:function(e){return e.length>0},validateString:function(e){return/\S/.test(e)},priority:512},type:{validateString:function(e,t){var i=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],n=i.step,r=void 0===n?"1":n,s=i.base,a=void 0===s?0:s,o=m[t];if(!o)throw new Error("validator type `"+t+"` is not supported");if(!o.test(e))return!1;if("number"===t&&!/^any$/i.test(r||"")){var l=Number(e),u=Math.pow(10,Math.max(y(r),y(a)));if((l*u-a*u)%(r*u)!=0)return!1}return!0},requirementType:{"":"string",step:"string",base:"number"},priority:256},pattern:{validateString:function(e,t){return t.test(e)},requirementType:"regexp",priority:64},minlength:{validateString:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxlength:{validateString:function(e,t){return e.length<=t},requirementType:"integer",priority:30},length:{validateString:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},mincheck:{validateMultiple:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxcheck:{validateMultiple:function(e,t){return e.length<=t},requirementType:"integer",priority:30},check:{validateMultiple:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},min:{validateNumber:function(e,t){return e>=t},requirementType:"number",priority:30},max:{validateNumber:function(e,t){return e<=t},requirementType:"number",priority:30},range:{validateNumber:function(e,t,i){return e>=t&&e<=i},requirementType:["number","number"],priority:30},equalto:{validateString:function(t,i){var n=e(i);return n.length?t===n.val():t===i},priority:256}}};var g=function(e){this.__class__="ParsleyUI"};g.prototype={listen:function(){var e=this;return window.Parsley.on("form:init",function(t){e.setupForm(t)}).on("field:init",function(t){e.setupField(t)}).on("field:validated",function(t){e.reflow(t)}).on("form:validated",function(t){e.focus(t)}).on("field:reset",function(t){e.reset(t)}).on("form:destroy",function(t){e.destroy(t)}).on("field:destroy",function(t){e.destroy(t)}),this},reflow:function(e){if("undefined"!=typeof e._ui&&!1!==e._ui.active){var t=this._diff(e.validationResult,e._ui.lastValidationResult);e._ui.lastValidationResult=e.validationResult,this.manageStatusClass(e),this.manageErrorsMessages(e,t),this.actualizeTriggers(e),(t.kept.length||t.added.length)&&!0!==e._ui.failedOnce&&this.manageFailingFieldTrigger(e)}},getErrorsMessages:function(e){if(!0===e.validationResult)return[];for(var t=[],i=0;i<e.validationResult.length;i++)t.push(e.validationResult[i].errorMessage||this._getErrorMessage(e,e.validationResult[i].assert));return t},manageStatusClass:function(e){e.hasConstraints()&&e.needsValidation()&&!0===e.validationResult?this._successClass(e):e.validationResult.length>0?this._errorClass(e):this._resetClass(e)},manageErrorsMessages:function(t,i){if("undefined"==typeof t.options.errorsMessagesDisabled){if("undefined"!=typeof t.options.errorMessage)return i.added.length||i.kept.length?(this._insertErrorWrapper(t),0===t._ui.$errorsWrapper.find(".parsley-custom-error-message").length&&t._ui.$errorsWrapper.append(e(t.options.errorTemplate).addClass("parsley-custom-error-message")),t._ui.$errorsWrapper.addClass("filled").find(".parsley-custom-error-message").html(t.options.errorMessage)):t._ui.$errorsWrapper.removeClass("filled").find(".parsley-custom-error-message").remove();for(var n=0;n<i.removed.length;n++)this.removeError(t,i.removed[n].assert.name,!0);for(n=0;n<i.added.length;n++)this.addError(t,i.added[n].assert.name,i.added[n].errorMessage,i.added[n].assert,!0);for(n=0;n<i.kept.length;n++)this.updateError(t,i.kept[n].assert.name,i.kept[n].errorMessage,i.kept[n].assert,!0)}},addError:function(t,i,n,r,s){this._insertErrorWrapper(t),t._ui.$errorsWrapper.addClass("filled").append(e(t.options.errorTemplate).addClass("parsley-"+i).html(n||this._getErrorMessage(t,r))),!0!==s&&this._errorClass(t)},updateError:function(e,t,i,n,r){e._ui.$errorsWrapper.addClass("filled").find(".parsley-"+t).html(i||this._getErrorMessage(e,n)),!0!==r&&this._errorClass(e)},removeError:function(e,t,i){e._ui.$errorsWrapper.removeClass("filled").find(".parsley-"+t).remove(),!0!==i&&this.manageStatusClass(e)},focus:function(e){if(e._focusedField=null,!0===e.validationResult||"none"===e.options.focus)return null;for(var t=0;t<e.fields.length;t++){var i=e.fields[t];if(!0!==i.validationResult&&i.validationResult.length>0&&"undefined"==typeof i.options.noFocus&&(e._focusedField=i.$element,"first"===e.options.focus))break}return null===e._focusedField?null:e._focusedField.focus()},_getErrorMessage:function(e,t){var i=t.name+"Message";return"undefined"!=typeof e.options[i]?window.Parsley.formatMessage(e.options[i],t.requirements):window.Parsley.getErrorMessage(t)},_diff:function(e,t,i){for(var n=[],r=[],s=0;s<e.length;s++){for(var a=!1,o=0;o<t.length;o++)if(e[s].assert.name===t[o].assert.name){a=!0;break}a?r.push(e[s]):n.push(e[s])}return{kept:r,added:n,removed:i?[]:this._diff(t,e,!0).added}},setupForm:function(e){e.$element.on("submit.Parsley",function(t){e.onSubmitValidate(t)}),e.$element.on("click.Parsley",'input[type="submit"], button[type="submit"]',function(t){e.onSubmitButton(t)}),!1!==e.options.uiEnabled&&e.$element.attr("novalidate","")},setupField:function(t){var i={active:!1};!1!==t.options.uiEnabled&&(i.active=!0,t.$element.attr(t.options.namespace+"id",t.__id__),i.$errorClassHandler=this._manageClassHandler(t),i.errorsWrapperId="parsley-id-"+(t.options.multiple?"multiple-"+t.options.multiple:t.__id__),i.$errorsWrapper=e(t.options.errorsWrapper).attr("id",i.errorsWrapperId),i.lastValidationResult=[],i.validationInformationVisible=!1,t._ui=i,this.actualizeTriggers(t))},_manageClassHandler:function(t){if("string"==typeof t.options.classHandler&&e(t.options.classHandler).length)return e(t.options.classHandler);var i=t.options.classHandler(t);return"undefined"!=typeof i&&i.length?i:!t.options.multiple||t.$element.is("select")?t.$element:t.$element.parent()},_insertErrorWrapper:function(t){var i;if(0!==t._ui.$errorsWrapper.parent().length)return t._ui.$errorsWrapper.parent();if("string"==typeof t.options.errorsContainer){if(e(t.options.errorsContainer).length)return e(t.options.errorsContainer).append(t._ui.$errorsWrapper);a.warn("The errors container `"+t.options.errorsContainer+"` does not exist in DOM")}else"function"==typeof t.options.errorsContainer&&(i=t.options.errorsContainer(t));if("undefined"!=typeof i&&i.length)return i.append(t._ui.$errorsWrapper);var n=t.$element;return t.options.multiple&&(n=n.parent()),n.after(t._ui.$errorsWrapper)},actualizeTriggers:function(e){var t=this,i=e._findRelated();if(i.off(".Parsley"),!1!==e.options.trigger){var n=e.options.trigger.replace(/^\s+/g,"").replace(/\s+$/g,"");""!==n&&i.on(n.split(" ").join(".Parsley ")+".Parsley",function(i){t.eventValidate(e,i)})}},eventValidate:function(e,t){/key/.test(t.type)&&!e._ui.validationInformationVisible&&e.getValue().length<=e.options.validationThreshold||e.validate()},manageFailingFieldTrigger:function(t){return t._ui.failedOnce=!0,t.options.multiple&&t._findRelated().each(function(){/change/i.test(e(this).parsley().options.trigger||"")||e(this).on("change.ParsleyFailedOnce",function(){t.validate()})}),t.$element.is("select")&&!/change/i.test(t.options.trigger||"")?t.$element.on("change.ParsleyFailedOnce",function(){t.validate()}):/keyup/i.test(t.options.trigger||"")?void 0:t.$element.on("keyup.ParsleyFailedOnce",function(){t.validate()})},reset:function(e){this.actualizeTriggers(e),e.$element.off(".ParsleyFailedOnce"),"undefined"!=typeof e._ui&&"ParsleyForm"!==e.__class__&&(e._ui.$errorsWrapper.removeClass("filled").children().remove(),this._resetClass(e),e._ui.lastValidationResult=[],e._ui.validationInformationVisible=!1,e._ui.failedOnce=!1)},destroy:function(e){this.reset(e),"ParsleyForm"!==e.__class__&&("undefined"!=typeof e._ui&&e._ui.$errorsWrapper.remove(),delete e._ui)},_successClass:function(e){e._ui.validationInformationVisible=!0,e._ui.$errorClassHandler.removeClass(e.options.errorClass).addClass(e.options.successClass)},_errorClass:function(e){e._ui.validationInformationVisible=!0,e._ui.$errorClassHandler.removeClass(e.options.successClass).addClass(e.options.errorClass)},_resetClass:function(e){e._ui.$errorClassHandler.removeClass(e.options.successClass).removeClass(e.options.errorClass)}};var v=function(t,i,n){this.__class__="ParsleyForm",this.__id__=a.generateID(),this.$element=e(t),this.domOptions=i,this.options=n,this.parent=window.Parsley,this.fields=[],this.validationResult=null},_={pending:null,resolved:!0,rejected:!1};v.prototype={onSubmitValidate:function(e){var t=this;if(!0!==e.parsley)return this._$submitSource=this._$submitSource||this.$element.find('input[type="submit"], button[type="submit"]').first(),this._$submitSource.is("[formnovalidate]")?void(this._$submitSource=null):(e.stopImmediatePropagation(),e.preventDefault(),this.whenValidate({event:e}).done(function(){t._submit()}).always(function(){t._$submitSource=null}),this)},onSubmitButton:function(t){this._$submitSource=e(t.target)},_submit:function(){!1!==this._trigger("submit")&&(this.$element.find(".parsley_synthetic_submit_button").remove(),this._$submitSource&&e('<input class="parsley_synthetic_submit_button" type="hidden">').attr("name",this._$submitSource.attr("name")).attr("value",this._$submitSource.attr("value")).appendTo(this.$element),this.$element.trigger(e.extend(e.Event("submit"),{parsley:!0})))},validate:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling validate on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1],s=i[2];t={group:n,force:r,event:s}}return _[this.whenValidate(t).state()]},whenValidate:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force,s=i.event;this.submitEvent=s,s&&(this.submitEvent.preventDefault=function(){a.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`"),t.validationResult=!1}),this.validationResult=!0,this._trigger("validate"),this._refreshFields();var o=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValidate({force:r,group:n})})}),l=function(){var i=e.Deferred();return!1===t.validationResult&&i.reject(),i.resolve().promise()};return e.when.apply(e,_toConsumableArray(o)).done(function(){t._trigger("success")}).fail(function(){t.validationResult=!1,t._trigger("error")}).always(function(){t._trigger("validated")}).pipe(l,l)},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={group:n,force:r}}return _[this.whenValid(t).state()]},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force;this._refreshFields();var s=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValid({group:n,force:r})})});return e.when.apply(e,_toConsumableArray(s))},_refreshFields:function(){return this.actualizeOptions()._bindFields()},_bindFields:function(){var t=this,i=this.fields;return this.fields=[],this.fieldsMappedById={},this._withoutReactualizingFormOptions(function(){t.$element.find(t.options.inputs).not(t.options.excluded).each(function(e,i){var n=new window.Parsley.Factory(i,{},t);"ParsleyField"!==n.__class__&&"ParsleyFieldMultiple"!==n.__class__||!0===n.options.excluded||"undefined"==typeof t.fieldsMappedById[n.__class__+"-"+n.__id__]&&(t.fieldsMappedById[n.__class__+"-"+n.__id__]=n,t.fields.push(n))}),e(i).not(t.fields).each(function(e,t){t._trigger("reset")})}),this},_withoutReactualizingFormOptions:function(e){var t=this.actualizeOptions;this.actualizeOptions=function(){return this};var i=e();return this.actualizeOptions=t,i},_trigger:function(e){return this.trigger("form:"+e)}};var w=function(t,i,n,r,s){if(!/ParsleyField/.test(t.__class__))throw new Error("ParsleyField or ParsleyFieldMultiple instance expected");var a=window.Parsley._validatorRegistry.validators[i],o=new f(a);e.extend(this,{validator:o,name:i,requirements:n,priority:r||t.options[i+"Priority"]||o.priority,isDomConstraint:!0===s}),this._parseRequirements(t.options)},b=function(e){var t=e[0].toUpperCase();return t+e.slice(1)};w.prototype={validate:function(e,t){var i=this.requirementList.slice(0);return i.unshift(e),i.push(t),this.validator.validate.apply(this.validator,i)},_parseRequirements:function(e){var t=this;this.requirementList=this.validator.parseRequirements(this.requirements,function(i){return e[t.name+b(i)]})}};var F=function(t,i,n,r){this.__class__="ParsleyField",this.__id__=a.generateID(),this.$element=e(t),"undefined"!=typeof r&&(this.parent=r),this.options=n,this.domOptions=i,this.constraints=[],this.constraintsByName={},this.validationResult=[],this._bindConstraints()},$={pending:null,resolved:!0,rejected:!1};F.prototype={validate:function(t){arguments.length>=1&&!e.isPlainObject(t)&&(a.warnOnce("Calling validate on a parsley field without passing arguments as an object is deprecated."),t={options:t});var i=this.whenValidate(t);if(!i)return!0;switch(i.state()){case"pending":return null;case"resolved":return!0;case"rejected":return this.validationResult}},whenValidate:function(){var e=this,t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],i=t.force,n=t.group;if(this.refreshConstraints(),!n||this._isInGroup(n))return this.value=this.getValue(),this._trigger("validate"),this.whenValid({force:i,value:this.value,_refreshed:!0}).done(function(){e._trigger("success")}).fail(function(){e._trigger("error")}).always(function(){e._trigger("validated")})},hasConstraints:function(){return 0!==this.constraints.length},needsValidation:function(e){return"undefined"==typeof e&&(e=this.getValue()),!(!e.length&&!this._isRequired()&&"undefined"==typeof this.options.validateIfEmpty)},_isInGroup:function(t){return e.isArray(this.options.group)?-1!==e.inArray(t,this.options.group):this.options.group===t},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley field without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={force:n,value:r}}var s=this.whenValid(t);return!s||$[s.state()]},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.force,r=void 0!==n&&n,s=i.value,a=i.group,o=i._refreshed;if(o||this.refreshConstraints(),!a||this._isInGroup(a)){if(this.validationResult=!0,!this.hasConstraints())return e.when();if("undefined"!=typeof s&&null!==s||(s=this.getValue()),!this.needsValidation(s)&&!0!==r)return e.when();var l=this._getGroupedConstraints(),u=[];return e.each(l,function(i,n){var r=e.when.apply(e,_toConsumableArray(e.map(n,function(e){return t._validateConstraint(s,e)})));if(u.push(r),"rejected"===r.state())return!1}),e.when.apply(e,u)}},_validateConstraint:function(t,i){var n=this,r=i.validate(t,this);return!1===r&&(r=e.Deferred().reject()),e.when(r).fail(function(e){!0===n.validationResult&&(n.validationResult=[]),n.validationResult.push({assert:i,errorMessage:"string"==typeof e&&e})})},getValue:function(){var e;return e="function"==typeof this.options.value?this.options.value(this):"undefined"!=typeof this.options.value?this.options.value:this.$element.val(),"undefined"==typeof e||null===e?"":this._handleWhitespace(e)},refreshConstraints:function(){return this.actualizeOptions()._bindConstraints()},addConstraint:function(e,t,i,n){if(window.Parsley._validatorRegistry.validators[e]){var r=new w(this,e,t,i,n);"undefined"!==this.constraintsByName[r.name]&&this.removeConstraint(r.name),this.constraints.push(r),this.constraintsByName[r.name]=r}return this},removeConstraint:function(e){for(var t=0;t<this.constraints.length;t++)if(e===this.constraints[t].name){this.constraints.splice(t,1);break}return delete this.constraintsByName[e],this},updateConstraint:function(e,t,i){return this.removeConstraint(e).addConstraint(e,t,i)},_bindConstraints:function(){for(var e=[],t={},i=0;i<this.constraints.length;i++)!1===this.constraints[i].isDomConstraint&&(e.push(this.constraints[i]),t[this.constraints[i].name]=this.constraints[i]);this.constraints=e,this.constraintsByName=t;for(var n in this.options)this.addConstraint(n,this.options[n],void 0,!0);return this._bindHtml5Constraints()},_bindHtml5Constraints:function(){(this.$element.hasClass("required")||this.$element.attr("required"))&&this.addConstraint("required",!0,void 0,!0),"string"==typeof this.$element.attr("pattern")&&this.addConstraint("pattern",this.$element.attr("pattern"),void 0,!0),"undefined"!=typeof this.$element.attr("min")&&"undefined"!=typeof this.$element.attr("max")?this.addConstraint("range",[this.$element.attr("min"),this.$element.attr("max")],void 0,!0):"undefined"!=typeof this.$element.attr("min")?this.addConstraint("min",this.$element.attr("min"),void 0,!0):"undefined"!=typeof this.$element.attr("max")&&this.addConstraint("max",this.$element.attr("max"),void 0,!0),"undefined"!=typeof this.$element.attr("minlength")&&"undefined"!=typeof this.$element.attr("maxlength")?this.addConstraint("length",[this.$element.attr("minlength"),this.$element.attr("maxlength")],void 0,!0):"undefined"!=typeof this.$element.attr("minlength")?this.addConstraint("minlength",this.$element.attr("minlength"),void 0,!0):"undefined"!=typeof this.$element.attr("maxlength")&&this.addConstraint("maxlength",this.$element.attr("maxlength"),void 0,!0);var e=this.$element.attr("type");return"undefined"==typeof e?this:"number"===e?this.addConstraint("type",["number",{step:this.$element.attr("step"),base:this.$element.attr("min")||this.$element.attr("value")}],void 0,!0):/^(email|url|range)$/i.test(e)?this.addConstraint("type",e,void 0,!0):this},_isRequired:function(){return"undefined"!=typeof this.constraintsByName.required&&!1!==this.constraintsByName.required.requirements},_trigger:function(e){return this.trigger("field:"+e)},_handleWhitespace:function(e){return!0===this.options.trimValue&&a.warnOnce('data-parsley-trim-value="true" is deprecated, please use data-parsley-whitespace="trim"'),"squish"===this.options.whitespace&&(e=e.replace(/\s{2,}/g," ")),"trim"!==this.options.whitespace&&"squish"!==this.options.whitespace&&!0!==this.options.trimValue||(e=a.trimString(e)),e},_getGroupedConstraints:function(){if(!1===this.options.priorityEnabled)return[this.constraints];for(var e=[],t={},i=0;i<this.constraints.length;i++){var n=this.constraints[i].priority;t[n]||e.push(t[n]=[]),t[n].push(this.constraints[i])}return e.sort(function(e,t){return t[0].priority-e[0].priority}),e}};var C=F,P=function(){this.__class__="ParsleyFieldMultiple"};P.prototype={addElement:function(e){return this.$elements.push(e),this},refreshConstraints:function(){var t;if(this.constraints=[],this.$element.is("select"))return this.actualizeOptions()._bindConstraints(),this;for(var i=0;i<this.$elements.length;i++)if(e("html").has(this.$elements[i]).length){t=this.$elements[i].data("ParsleyFieldMultiple").refreshConstraints().constraints;for(var n=0;n<t.length;n++)this.addConstraint(t[n].name,t[n].requirements,t[n].priority,t[n].isDomConstraint)}else this.$elements.splice(i,1);return this},getValue:function(){if("function"==typeof this.options.value)value=this.options.value(this);else if("undefined"!=typeof this.options.value)return this.options.value;if(this.$element.is("input[type=radio]"))return this._findRelated().filter(":checked").val()||"";if(this.$element.is("input[type=checkbox]")){var t=[];return this._findRelated().filter(":checked").each(function(){t.push(e(this).val())}),t}return this.$element.is("select")&&null===this.$element.val()?[]:this.$element.val()},_init:function(){return this.$elements=[this.$element],this}};var x=function(t,i,n){this.$element=e(t);var r=this.$element.data("Parsley");if(r)return"undefined"!=typeof n&&r.parent===window.Parsley&&(r.parent=n,r._resetOptions(r.options)),r;if(!this.$element.length)throw new Error("You must bind Parsley on an existing element.");if("undefined"!=typeof n&&"ParsleyForm"!==n.__class__)throw new Error("Parent instance must be a ParsleyForm instance");return this.parent=n||window.Parsley,this.init(i)};x.prototype={init:function(e){return this.__class__="Parsley",this.__version__="@@version",this.__id__=a.generateID(),this._resetOptions(e),this.$element.is("form")||a.checkAttr(this.$element,this.options.namespace,"validate")&&!this.$element.is(this.options.inputs)?this.bind("parsleyForm"):this.isMultiple()?this.handleMultiple():this.bind("parsleyField")},isMultiple:function(){return this.$element.is("input[type=radio], input[type=checkbox]")||this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple")},handleMultiple:function(){var t,i,n=this;if(this.options.multiple||("undefined"!=typeof this.$element.attr("name")&&this.$element.attr("name").length?this.options.multiple=t=this.$element.attr("name"):"undefined"!=typeof this.$element.attr("id")&&this.$element.attr("id").length&&(this.options.multiple=this.$element.attr("id"))),this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple"))return this.options.multiple=this.options.multiple||this.__id__,this.bind("parsleyFieldMultiple");if(!this.options.multiple)return a.warn("To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.",this.$element),this;this.options.multiple=this.options.multiple.replace(/(:|\.|\[|\]|\{|\}|\$)/g,""),"undefined"!=typeof t&&e('input[name="'+t+'"]').each(function(t,i){e(i).is("input[type=radio], input[type=checkbox]")&&e(i).attr(n.options.namespace+"multiple",n.options.multiple)});for(var r=this._findRelated(),s=0;s<r.length;s++)if(i=e(r.get(s)).data("Parsley"),"undefined"!=typeof i){this.$element.data("ParsleyFieldMultiple")||i.addElement(this.$element);
break}return this.bind("parsleyField",!0),i||this.bind("parsleyFieldMultiple")},bind:function(t,i){var n;switch(t){case"parsleyForm":n=e.extend(new v(this.$element,this.domOptions,this.options),window.ParsleyExtend)._bindFields();break;case"parsleyField":n=e.extend(new C(this.$element,this.domOptions,this.options,this.parent),window.ParsleyExtend);break;case"parsleyFieldMultiple":n=e.extend(new C(this.$element,this.domOptions,this.options,this.parent),new P,window.ParsleyExtend)._init();break;default:throw new Error(t+"is not a supported Parsley type")}return this.options.multiple&&a.setAttr(this.$element,this.options.namespace,"multiple",this.options.multiple),"undefined"!=typeof i?(this.$element.data("ParsleyFieldMultiple",n),n):(this.$element.data("Parsley",n),n._trigger("init"),n)}};var V=e.fn.jquery.split(".");if(parseInt(V[0])<=1&&parseInt(V[1])<8)throw"The loaded version of jQuery is too old. Please upgrade to 1.8.x or better.";V.forEach||a.warn("Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim");var E=e.extend(new l,{$element:e(document),actualizeOptions:null,_resetOptions:null,Factory:x,version:"@@version"});e.extend(C.prototype,l.prototype),e.extend(v.prototype,l.prototype),e.extend(x.prototype,l.prototype),e.fn.parsley=e.fn.psly=function(t){if(this.length>1){var i=[];return this.each(function(){i.push(e(this).parsley(t))}),i}return e(this).length?new x(this,t):void a.warn("You must bind Parsley on an existing element.")},"undefined"==typeof window.ParsleyExtend&&(window.ParsleyExtend={}),E.options=e.extend(a.objectCreate(o),window.ParsleyConfig),window.ParsleyConfig=E.options,window.Parsley=window.psly=E,window.ParsleyUtils=a;var M=window.Parsley._validatorRegistry=new c(window.ParsleyConfig.validators,window.ParsleyConfig.i18n);window.ParsleyValidator={},e.each("setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator".split(" "),function(t,i){window.Parsley[i]=e.proxy(M,i),window.ParsleyValidator[i]=function(){var e;return a.warnOnce("Accessing the method '"+i+"' through ParsleyValidator is deprecated. Simply call 'window.Parsley."+i+"(...)'"),(e=window.Parsley)[i].apply(e,arguments)}}),window.ParsleyUI="function"==typeof window.ParsleyConfig.ParsleyUI?(new window.ParsleyConfig.ParsleyUI).listen():(new g).listen(),!1!==window.ParsleyConfig.autoBind&&e(function(){e("[data-parsley-validate]").length&&e("[data-parsley-validate]").parsley()});var O=e({}),R=function(){a.warnOnce("Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley")},D="parsley:";e.listen=function(e,n){var r;if(R(),"object"==typeof arguments[1]&&"function"==typeof arguments[2]&&(r=arguments[1],n=arguments[2]),"function"!=typeof n)throw new Error("Wrong parameters");window.Parsley.on(i(e),t(n,r))},e.listenTo=function(e,n,r){if(R(),!(e instanceof C||e instanceof v))throw new Error("Must give Parsley instance");if("string"!=typeof n||"function"!=typeof r)throw new Error("Wrong parameters");e.on(i(n),t(r))},e.unsubscribe=function(e,t){if(R(),"string"!=typeof e||"function"!=typeof t)throw new Error("Wrong arguments");window.Parsley.off(i(e),t.parsleyAdaptedCallback)},e.unsubscribeTo=function(e,t){if(R(),!(e instanceof C||e instanceof v))throw new Error("Must give Parsley instance");e.off(i(t))},e.unsubscribeAll=function(t){R(),window.Parsley.off(i(t)),e("form,input,textarea,select").each(function(){var n=e(this).data("Parsley");n&&n.off(i(t))})},e.emit=function(e,t){var n;R();var r=t instanceof C||t instanceof v,s=Array.prototype.slice.call(arguments,r?2:1);s.unshift(i(e)),r||(t=window.Parsley),(n=t).trigger.apply(n,_toConsumableArray(s))};e.extend(!0,E,{asyncValidators:{"default":{fn:function(e){return e.status>=200&&e.status<300},url:!1},reverse:{fn:function(e){return e.status<200||e.status>=300},url:!1}},addAsyncValidator:function(e,t,i,n){return E.asyncValidators[e]={fn:t,url:i||!1,options:n||{}},this}}),E.addValidator("remote",{requirementType:{"":"string",validator:"string",reverse:"boolean",options:"object"},validateString:function(t,i,n,r){var s,a,o={},l=n.validator||(!0===n.reverse?"reverse":"default");if("undefined"==typeof E.asyncValidators[l])throw new Error("Calling an undefined async validator: `"+l+"`");i=E.asyncValidators[l].url||i,i.indexOf("{value}")>-1?i=i.replace("{value}",encodeURIComponent(t)):o[r.$element.attr("name")||r.$element.attr("id")]=t;var u=e.extend(!0,n.options||{},E.asyncValidators[l].options);s=e.extend(!0,{},{url:i,data:o,type:"GET"},u),r.trigger("field:ajaxoptions",r,s),a=e.param(s),"undefined"==typeof E._remoteCache&&(E._remoteCache={});var d=E._remoteCache[a]=E._remoteCache[a]||e.ajax(s),h=function(){var t=E.asyncValidators[l].fn.call(r,d,i,n);return t||(t=e.Deferred().reject()),e.when(t)};return d.then(h,h)},priority:-1}),E.on("form:submit",function(){E._remoteCache={}}),window.ParsleyExtend.addAsyncValidator=function(){return ParsleyUtils.warnOnce("Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`"),E.addAsyncValidator.apply(E,arguments)},E.addMessages("en",{defaultMessage:"This value seems to be invalid.",type:{email:"This value should be a valid email.",url:"This value should be a valid url.",number:"This value should be a valid number.",integer:"This value should be a valid integer.",digits:"This value should be digits.",alphanum:"This value should be alphanumeric."},notblank:"This value should not be blank.",required:"This value is required.",pattern:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or fewer.",length:"This value length is invalid. It should be between %s and %s characters long.",mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or fewer.",check:"You must select between %s and %s choices.",equalto:"This value should be the same."}),E.setLocale("en");var q=E;return q});
jQuery(document).ready(function(e){function a(e,a){l(e,a),e.find(a.container).first().show()}function n(a,n){if(n.tabs){var t=e("<div />",{"class":n.tabMenuClassName}).insertBefore(a.children(n.container).filter(":first"));a.children(n.container).each(function(i,r){var l=e("<button/>").html(e(this).children(n.header).html()).addClass(0==i?n.tabMenuItemActiveClassName:"").addClass("item"+i).addClass("btn btn-default").prop("type","button").on("click keypress",{container:a.children(n.container),fieldset:e(r)},function(){var t=e(this),i=t.parent().children().index(t);s(a,n,t,i)});n.tabIndex&&l.prop("tabindex",i),t.append(l)})}}function t(a,n){n.navigation&&a.children(n.container).each(function(t){var i=e("<div />").addClass("powermail_fieldwrap").addClass("powermail_tab_navigation").appendTo(e(this));t>0&&i.append(c(a,n)),t<a.children(n.container).length-1&&i.append(o(a,n))})}function i(a,n){e.fn.parsley&&"data-parsley-validate"===a.data("parsley-validate")&&a.parsley().subscribe("parsley:field:validated",function(){v(a,n),C(a,n)})}function r(a,n){n.openTabOnError&&e.listen("parsley:field:error",function(){setTimeout(function(){a.find("."+n.tabMenuClassName+" > ."+n.tabMenuItemErrorClassName+":first").click()},50)})}function s(a,n,t,i){$activeTab=p(a,n),$activeTab.removeClass(n.tabMenuItemActiveClassName),t.addClass(n.tabMenuItemActiveClassName),l(a,n),e(".powermail_fieldset",a).slice(i,i+1).show()}function l(e,a){e.children(a.container).hide()}function c(a,n){return e("<a />").prop("href","#").addClass("btn btn-warning").html("<").click(function(e){e.preventDefault(),u(a,n)})}function o(a,n){return e("<a />").prop("href","#").addClass("btn btn-primary pull-right").html(">").click(function(e){e.preventDefault(),d(a,n)})}function d(e,a){var n=m(e,a);$activeTab=p(e,a),$activeTab.removeClass(a.tabMenuItemActiveClassName).next().addClass(a.tabMenuItemActiveClassName),f(e,a,n+1)}function u(e,a){var n=m(e,a);$activeTab=p(e,a),$activeTab.removeClass(a.tabMenuItemActiveClassName).prev().addClass(a.tabMenuItemActiveClassName),f(e,a,n-1)}function f(e,a,n){l(e,a),e.find(".powermail_fieldset").slice(n,n+1).show()}function m(e,a){var n=b(e,a),t=n.index(p(e,a));return parseInt(t)}function b(e,a){return e.find("."+a.tabMenuClassName).children()}function p(e,a){var n=b(e,a);return n.filter("."+a.tabMenuItemActiveClassName)}function v(e,a){var n=b(e,a);n.removeClass(a.tabMenuItemErrorClassName)}function C(a,n){a.parsley().isValid()||a.find(".parsley-error").each(function(){var t=a.find(".powermail_fieldset").index(e(this).closest(".powermail_fieldset")),i=b(a,n),r=i.slice(t,t+1);r.addClass(n.tabMenuItemErrorClassName)})}e.fn.powermailTabs=function(e){"use strict";var s=jQuery(this);e=jQuery.extend({container:"fieldset",header:"legend",tabs:!0,navigation:!0,openTabOnError:!0,tabIndex:!0,tabMenuClassName:"btn-group",tabMenuItemActiveClassName:"btn-primary",tabMenuItemErrorClassName:"btn-danger"},e),a(s,e),n(s,e),t(s,e),i(s,e),r(s,e)}});
function PowermailForm(e){"use strict";this.initialize=function(){a(),t(),i(),r(),o(),n(),c(),l()};var a=function(){e.fn.powermailTabs&&e(".powermail_morestep").each(function(){e(this).powermailTabs()})},t=function(){e("form[data-powermail-ajax]").length&&p()},i=function(){if(e('*[data-powermail-location="prefill"]').length&&navigator.geolocation){e(this);navigator.geolocation.getCurrentPosition(function(a){var t=a.coords.latitude,i=a.coords.longitude,r=j()+"/index.php?eID=powermailEidGetLocation";jQuery.ajax({url:r,data:"lat="+t+"&lng="+i,cache:!1,success:function(a){a&&e('*[data-powermail-location="prefill"]').val(a)}})})}},r=function(){e.fn.datetimepicker&&e(".powermail_date").each(function(){var a=e(this);if("date"===a.prop("type")||"datetime-local"===a.prop("type")||"time"===a.prop("type")){if(!a.data("datepicker-force")){if(e(this).data("date-value")){var t=v(e(this).data("date-value"),e(this).data("datepicker-format"),a.prop("type"));null!==t&&e(this).val(t)}return}a.prop("type","text")}var i=!0,r=!0;"date"===a.data("datepicker-settings")?r=!1:"time"===a.data("datepicker-settings")&&(i=!1),a.datetimepicker({format:a.data("datepicker-format"),timepicker:r,datepicker:i,lang:"en",i18n:{en:{months:a.data("datepicker-months").split(","),dayOfWeek:a.data("datepicker-days").split(",")}}})})},o=function(){e(".powermail_all_type_password.powermail_all_value").html("********")},n=function(){e.fn.parsley&&e(".powermail_reset").on("click","",function(){e('form[data-parsley-validate="data-parsley-validate"]').parsley().reset()})},l=function(){window.Parsley&&(_(),x())},p=function(){var a,t=!1;e(document).on("submit","form[data-powermail-ajax]",function(i){var r=e(this);r.data("powermail-ajax-uri")&&(a=r.data("powermail-ajax-uri"));var o=r.data("powermail-form");t||(e.ajax({type:"POST",url:r.prop("action"),data:new FormData(r.get(0)),contentType:!1,processData:!1,beforeSend:function(){s(r)},complete:function(){d(r),c()},success:function(i){var n=e('*[data-powermail-form="'+o+'"]:first',i);n.length?(e('*[data-powermail-form="'+o+'"]:first').closest(".tx-powermail").html(n),e.fn.powermailTabs&&e(".powermail_morestep").powermailTabs(),e.fn.parsley&&e('form[data-parsley-validate="data-parsley-validate"]').parsley(),m()):(a?window.location=a:r.submit(),t=!0)}}),i.preventDefault())})},s=function(a){d(a),e(".powermail_submit",a).length?e(".powermail_submit",a).parent().append(g()):a.closest(".tx-powermail").append(g())},d=function(e){e.closest(".tx-powermail").find(".powermail_progressbar").remove()},c=function(){e(".powermail_fieldwrap_file").find(".deleteAllFiles").each(function(){f(e(this).closest(".powermail_fieldwrap_file").find('input[type="file"]'))}),e(".deleteAllFiles").click(function(){u(e(this).closest(".powermail_fieldwrap_file").find('input[type="hidden"]')),e(this).closest("ul").fadeOut(function(){e(this).remove()})})},f=function(e){e.prop("disabled","disabled").addClass("hide").prop("type","hidden")},u=function(e){e.prop("disabled",!1).removeClass("hide").prop("type","file")},m=function(){e("img.powermail_captchaimage").each(function(){var a=w(e(this).prop("src"));e(this).prop("src",a+"?hash="+h(5))})},w=function(e){var a=e.split("?");return a[0]},h=function(e){for(var a="",t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",i=0;i<e;i++)a+=t.charAt(Math.floor(Math.random()*t.length));return a},v=function(e,a,t){var i=Date.parseDate(e,a);if(null===i)return null;var r=new Date(i),o=r.getFullYear()+"-";o+=("0"+(r.getMonth()+1)).slice(-2)+"-",o+=("0"+r.getDate()).slice(-2);var n=("0"+r.getHours()).slice(-2)+":"+("0"+r.getMinutes()).slice(-2),l=o+"T"+n;return"date"===t?o:"datetime-local"===t?l:"time"===t?n:null},g=function(){return e("<div />").addClass("powermail_progressbar").html(e("<div />").addClass("powermail_progress").html(e("<div />").addClass("powermail_progess_inner")))},y=function(e){for(var a=e.get(0),t=0,i=0;i<a.files.length;i++){var r=a.files[i];r.size>t&&(t=r.size)}return parseInt(t)},_=function(){window.Parsley.addValidator("powermailfilesize",function(a,t){if(t.indexOf(",")!==-1){var i=t.split(","),r=parseInt(i[0]),o=e('*[name="tx_powermail_pi1[field]['+i[1]+'][]"]');if(o.length&&y(o)>r)return!1}return!0},32).addMessage("en","powermailfilesize","Error")},x=function(){window.Parsley.addValidator("powermailfileextensions",function(a,t){var i=e('*[name="tx_powermail_pi1[field]['+t+'][]"]');return!i.length||b(k(a),i.prop("accept"))},32).addMessage("en","powermailfileextensions","Error")},b=function(e,a){return a.indexOf("."+e)!==-1},k=function(e){return e.split(".").pop().toLowerCase()},j=function(){var a;return a=e("base").length>0?jQuery("base").prop("href"):"https:"!=window.location.protocol?"http://"+window.location.hostname:"https://"+window.location.hostname}}jQuery(document).ready(function(e){"use strict";var a=new window.PowermailForm(e);a.initialize()});
let cookieContainer = null;

if (localStorage.getItem('cookie_googleAnalytics')==null || localStorage.getItem('cookie_googleAnalytics')===undefined) {
    localStorage.setItem('cookie_googleAnalytics',false);
}
if (localStorage.getItem('cookie_facebook')==null || localStorage.getItem('cookie_facebook')===undefined) {
    localStorage.setItem('cookie_facebook',false);
}
if (localStorage.getItem('cookie_tagManager')==null || localStorage.getItem('cookie_tagManager')===undefined) {
    localStorage.setItem('cookie_tagManager',false);
}
if (localStorage.getItem('cookie_matomo')==null || localStorage.getItem('cookie_matomo')===undefined) {
    localStorage.setItem('cookie_matomo',false);
}
if (localStorage.getItem('cookie_removeCookieWindow')==null || localStorage.getItem('cookie_removeCookieWindow')===undefined) {
    localStorage.setItem('cookie_removeCookieWindow',false);
}

$(document).ready(function () {

    cookieContainer = $('.cookie-container');
    showCookieWindow();
    setCookieHeight();

    /**
     * cookies revoked
     */
    $('.cookie-outer-container-wrap .revoke').click(function () {
        localStorage.setItem('cookie_googleAnalytics',false);
        localStorage.setItem('cookie_facebook',false);
        localStorage.setItem('cookie_tagManager',false);
        localStorage.setItem('cookie_matomo',false);
        localStorage.setItem('cookie_removeCookieWindow',true);
        $('.cookie-container-settings').hide();
        cookieContainer.hide();
    });

    /**
     * load cookies after button accept
     */
    $('.cookie-outer-container-wrap .accept-all').click(function () {
        localStorage.setItem('cookie_googleAnalytics',true);
        localStorage.setItem('cookie_facebook',true);
        localStorage.setItem('cookie_tagManager',true);
        localStorage.setItem('cookie_matomo',true);
        localStorage.setItem('cookie_removeCookieWindow',true);
        loadCookie();
        $('.cookie-container-settings').hide();
        cookieContainer.hide();
    });

    /**
     * load cookies - show only hint
     */
    $('.cookie-outer-container-wrap .notice').click(function () {
        localStorage.setItem('cookie_removeCookieWindow',true);
        cookieContainer.hide();
    });
    if ($('.cookie-container.optin_0').length && localStorage.getItem('cookie_optin') != 'true' ) {
        localStorage.setItem('cookie_googleAnalytics',true);
        localStorage.setItem('cookie_facebook',true);
        localStorage.setItem('cookie_tagManager',true);
        localStorage.setItem('cookie_matomo',true);
        localStorage.setItem('cookie_optin',true);
    }

    /**
     * open cookie settings
     */
    $('.cookie-outer-container-wrap .settings').click(function () {
        $('.cookie-container-settings').show();
    });

    /**
     * edit cookie settings - privacy page
     */
    $('.cookie-settings-button').click(function () {
        preSelectSettings();
        $('.cookie-container-settings').show();
    });

    /**
     * close cookie option window
     */
    $('.cookie-container-settings').click(function (e) {
        if (!$(this).parents('.cookie-container-popup').length && $(e.target)[0].className == 'inner-cookie-container-settings') {
            $('.cookie-container-settings').hide();
        }
    });

    /**
     * save cookie settings
     */
    $('.cookie-outer-container-wrap .save-settings').click(function () {
        $('.cookie-container-settings').hide();
        cookieContainer.hide();
        localStorage.setItem('cookie_removeCookieWindow',true);

        localStorage.setItem('cookie_googleAnalytics',false);
        localStorage.setItem('cookie_facebook',false);
        localStorage.setItem('cookie_tagManager',false);
        localStorage.setItem('cookie_matomo',false);

        if($('.cookie-container-settings #googleAnalytics-cookie').is(':checked')) {
            localStorage.setItem('cookie_googleAnalytics',true);
        }
        if($('.cookie-container-settings #tagmanager-cookie').is(':checked')) {
            localStorage.setItem('cookie_tagManager',true);
        }
        if($('.cookie-container-settings #facebook-cookie').is(':checked')) {
            localStorage.setItem('cookie_facebook',true);
        }
        if($('.cookie-container-settings #matomo-cookie').is(':checked')) {
            localStorage.setItem('cookie_matomo',true);
        }
        loadCookie();
    });

    /**
     * load cookies on page load
     */
    loadCookie();

    /**
     * set checkboxes on user input
     */
    preSelectSettings();

    /**
     * place cookie settings button on privacy page
     */
    placeCookieSettings();
});

$(window).resize(function () {
    setCookieHeight();
});

function setCookieHeight() {
    if (cookieContainer != null) {
        if (cookieContainer.hasClass('top') || cookieContainer.hasClass('bottom')) {
            if (cookieContainer.hasClass('bottom')) {
                $('body').css('paddingBottom',cookieContainer.outerHeight()+'px');
            }
            if (cookieContainer.hasClass('top')) {
                if (cookieContainer.css('position')=='fixed') {
                    $('body').css('paddingTop','0');
                } else {
                    $('body').css('paddingTop',cookieContainer.outerHeight()+'px');
                }
            }
        }
    }
}

function loadCookie() {

    if (localStorage.getItem('cookie_facebook') == 'true') {
        if ($('.script-container .facebook-script').text().length) {
            // no script
            let noScriptSource = $('.script-container .facebook-no-script').data('src');
            let img = '<img height="1" width="1" style="display:none" src="'+noScriptSource+'"/>';
            let noScript = $('.script-container .facebook-no-script noscript').html(img);
            $('body').prepend(noScript);

            // normal script
            let script = $('<script></script>').text($('.script-container .facebook-script').text());
            $('head').append(script[0]);
            $('.script-container .facebook-no-script').remove();
            $('.script-container .facebook-script').remove();
        }
    }

    if (localStorage.getItem('cookie_tagManager') == 'true') {
        if ($('.script-container .tagManager').text().length) {
            // no script
            let noScriptSource = $('.script-container .tagManager-no-script').data('src');
            let iframe = '<iframe src="' + noScriptSource + '" height="0" width="0" style="display:none;visibility:hidden"></iframe>';
            let noScript = $('.script-container .tagManager-no-script noscript').html(iframe);
            $('body').prepend(noScript);

            // normal script
            let script = $('<script></script>').text($('.script-container .tagManager').text());
            $('head').append(script[0]);
            $('.script-container .tagManager-no-script').remove();
            $('.script-container .tagManager').remove();
        }
    }

    if (localStorage.getItem('cookie_googleAnalytics') == 'true') {
        if ($('.script-container .googleAnalytics').text().length) {
            // script
            let scriptSource = $('.script-container .googleAnalytics').data('src');
            let headScript = '<script src="'+scriptSource+'" async ></script>';
            $('head').prepend(headScript);

            // script
            let script = $('<script></script>').text($('.script-container .googleAnalytics').text());
            $('head').append(script[0]);
            $('.script-container .googleAnalytics').remove();

        }
    }

    if (localStorage.getItem('cookie_matomo') == 'true') {
        if ($('.script-container .matomo-script').text().length) {
            // script
            let script = $('<script></script>').text($('.script-container .matomo-script').text());
            $('head').append(script[0]);
            $('.script-container .matomo-script').remove();
        }
    }
}

// pre select in settings window
function preSelectSettings() {

    if (localStorage.getItem('cookie_facebook') == 'true') {
        $('#facebook-cookie').prop( "checked", true );
    } else {
        $('#facebook-cookie').prop( "checked", false );
    }

    if (localStorage.getItem('cookie_tagManager') == 'true') {
        $('#tagmanager-cookie').prop( "checked", true );
    }

    if (localStorage.getItem('cookie_googleAnalytics') == 'true') {
        $('#googleAnalytics-cookie').prop( "checked", true );
    }

    if (localStorage.getItem('cookie_matomo') == 'true') {
        $('#matomo-cookie').prop( "checked", true );
    }

}

function showCookieWindow() {
    if (localStorage.getItem('cookie_removeCookieWindow') == 'false') {
        cookieContainer.show();
        if ($('.cookie-outer-container-wrap.popup').length) {
            $('.cookie-container-settings:not(".privacy-page")').show();
        }
    } else if (localStorage.getItem('cookie_removeCookieWindow') == 'true') {
        cookieContainer.hide();
    }
}

function placeCookieSettings() {
    let main = $('body > main').first(),
        content = $('body > .content').first();

    if (main.length) {
        placeCookieButton(main);
    } else if (content.length) {
        placeCookieButton(content);
    }
}

function placeCookieButton(elem) {
    elem.prepend($('.cookie-privacy-container'));
}
try{Typekit.load({ async: true });}catch(e){}