/**!![core]>!!**/
(function(){
/*!
 * https://github.com/es-shims/es5-shim
 * @license es5-shim Copyright 2009-2014 by contributors, MIT License
 * see https://github.com/es-shims/es5-shim/blob/master/LICENSE
 */

// vim: ts=4 sts=4 sw=4 expandtab

//Add semicolon to prevent IIFE from being passed as argument to concatenated code.
;

// UMD (Universal Module Definition)
// see https://github.com/umdjs/umd/blob/master/returnExports.js
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(factory);
    } else if (typeof exports === 'object') {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like enviroments that support module.exports,
        // like Node.
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        root.returnExports = factory();
    }
}(this, function () {

/**
 * Brings an environment as close to ECMAScript 5 compliance
 * as is possible with the facilities of erstwhile engines.
 *
 * Annotated ES5: http://es5.github.com/ (specific links below)
 * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
 * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/
 */

// Shortcut to an often accessed properties, in order to avoid multiple
// dereference that costs universally.
var ArrayPrototype = Array.prototype;
var ObjectPrototype = Object.prototype;
var FunctionPrototype = Function.prototype;
var StringPrototype = String.prototype;
var NumberPrototype = Number.prototype;
var array_slice = ArrayPrototype.slice;
var array_splice = ArrayPrototype.splice;
var array_push = ArrayPrototype.push;
var array_unshift = ArrayPrototype.unshift;
var call = FunctionPrototype.call;

// Having a toString local variable name breaks in Opera so use _toString.
var _toString = ObjectPrototype.toString;

var isFunction = function (val) {
    return ObjectPrototype.toString.call(val) === '[object Function]';
};
var isRegex = function (val) {
    return ObjectPrototype.toString.call(val) === '[object RegExp]';
};
var isArray = function isArray(obj) {
    return _toString.call(obj) === "[object Array]";
};
var isString = function isString(obj) {
    return _toString.call(obj) === "[object String]";
};
var isArguments = function isArguments(value) {
    var str = _toString.call(value);
    var isArgs = str === '[object Arguments]';
    if (!isArgs) {
        isArgs = !isArray(value)
            && value !== null
            && typeof value === 'object'
            && typeof value.length === 'number'
            && value.length >= 0
            && isFunction(value.callee);
    }
    return isArgs;
};

var supportsDescriptors = Object.defineProperty && (function () {
    try {
        Object.defineProperty({}, 'x', {});
        return true;
    } catch (e) { /* this is ES3 */
        return false;
    }
}());

// Define configurable, writable and non-enumerable props
// if they don't exist.
var defineProperty;
if (supportsDescriptors) {
    defineProperty = function (object, name, method, forceAssign) {
        if (!forceAssign && (name in object)) { return; }
        Object.defineProperty(object, name, {
            configurable: true,
            enumerable: false,
            writable: true,
            value: method
        });
    };
} else {
    defineProperty = function (object, name, method, forceAssign) {
        if (!forceAssign && (name in object)) { return; }
        object[name] = method;
    };
}
var defineProperties = function (object, map, forceAssign) {
    for (var name in map) {
        if (ObjectPrototype.hasOwnProperty.call(map, name)) {
          defineProperty(object, name, map[name], forceAssign);
        }
    }
};

//
// Util
// ======
//

// ES5 9.4
// http://es5.github.com/#x9.4
// http://jsperf.com/to-integer

function toInteger(n) {
    n = +n;
    if (n !== n) { // isNaN
        n = 0;
    } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
        n = (n > 0 || -1) * Math.floor(Math.abs(n));
    }
    return n;
}

function isPrimitive(input) {
    var type = typeof input;
    return (
        input === null ||
        type === "undefined" ||
        type === "boolean" ||
        type === "number" ||
        type === "string"
    );
}

function toPrimitive(input) {
    var val, valueOf, toStr;
    if (isPrimitive(input)) {
        return input;
    }
    valueOf = input.valueOf;
    if (isFunction(valueOf)) {
        val = valueOf.call(input);
        if (isPrimitive(val)) {
            return val;
        }
    }
    toStr = input.toString;
    if (isFunction(toStr)) {
        val = toStr.call(input);
        if (isPrimitive(val)) {
            return val;
        }
    }
    throw new TypeError();
}

// ES5 9.9
// http://es5.github.com/#x9.9
var toObject = function (o) {
    if (o == null) { // this matches both null and undefined
        throw new TypeError("can't convert " + o + " to object");
    }
    return Object(o);
};

var ToUint32 = function ToUint32(x) {
    return x >>> 0;
};

//
// Function
// ========
//

// ES-5 15.3.4.5
// http://es5.github.com/#x15.3.4.5

function Empty() {}

defineProperties(FunctionPrototype, {
    bind: function bind(that) { // .length is 1
        // 1. Let Target be the this value.
        var target = this;
        // 2. If IsCallable(Target) is false, throw a TypeError exception.
        if (!isFunction(target)) {
            throw new TypeError("Function.prototype.bind called on incompatible " + target);
        }
        // 3. Let A be a new (possibly empty) internal list of all of the
        //   argument values provided after thisArg (arg1, arg2 etc), in order.
        // XXX slicedArgs will stand in for "A" if used
        var args = array_slice.call(arguments, 1); // for normal call
        // 4. Let F be a new native ECMAScript object.
        // 11. Set the [[Prototype]] internal property of F to the standard
        //   built-in Function prototype object as specified in 15.3.3.1.
        // 12. Set the [[Call]] internal property of F as described in
        //   15.3.4.5.1.
        // 13. Set the [[Construct]] internal property of F as described in
        //   15.3.4.5.2.
        // 14. Set the [[HasInstance]] internal property of F as described in
        //   15.3.4.5.3.
        var binder = function () {

            if (this instanceof bound) {
                // 15.3.4.5.2 [[Construct]]
                // When the [[Construct]] internal method of a function object,
                // F that was created using the bind function is called with a
                // list of arguments ExtraArgs, the following steps are taken:
                // 1. Let target be the value of F's [[TargetFunction]]
                //   internal property.
                // 2. If target has no [[Construct]] internal method, a
                //   TypeError exception is thrown.
                // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
                //   property.
                // 4. Let args be a new list containing the same values as the
                //   list boundArgs in the same order followed by the same
                //   values as the list ExtraArgs in the same order.
                // 5. Return the result of calling the [[Construct]] internal
                //   method of target providing args as the arguments.

                var result = target.apply(
                    this,
                    args.concat(array_slice.call(arguments))
                );
                if (Object(result) === result) {
                    return result;
                }
                return this;

            } else {
                // 15.3.4.5.1 [[Call]]
                // When the [[Call]] internal method of a function object, F,
                // which was created using the bind function is called with a
                // this value and a list of arguments ExtraArgs, the following
                // steps are taken:
                // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
                //   property.
                // 2. Let boundThis be the value of F's [[BoundThis]] internal
                //   property.
                // 3. Let target be the value of F's [[TargetFunction]] internal
                //   property.
                // 4. Let args be a new list containing the same values as the
                //   list boundArgs in the same order followed by the same
                //   values as the list ExtraArgs in the same order.
                // 5. Return the result of calling the [[Call]] internal method
                //   of target providing boundThis as the this value and
                //   providing args as the arguments.

                // equiv: target.call(this, ...boundArgs, ...args)
                return target.apply(
                    that,
                    args.concat(array_slice.call(arguments))
                );

            }

        };

        // 15. If the [[Class]] internal property of Target is "Function", then
        //     a. Let L be the length property of Target minus the length of A.
        //     b. Set the length own property of F to either 0 or L, whichever is
        //       larger.
        // 16. Else set the length own property of F to 0.

        var boundLength = Math.max(0, target.length - args.length);

        // 17. Set the attributes of the length own property of F to the values
        //   specified in 15.3.5.1.
        var boundArgs = [];
        for (var i = 0; i < boundLength; i++) {
            boundArgs.push("$" + i);
        }

        // XXX Build a dynamic function with desired amount of arguments is the only
        // way to set the length property of a function.
        // In environments where Content Security Policies enabled (Chrome extensions,
        // for ex.) all use of eval or Function costructor throws an exception.
        // However in all of these environments Function.prototype.bind exists
        // and so this code will never be executed.
        var bound = Function("binder", "return function (" + boundArgs.join(",") + "){return binder.apply(this,arguments)}")(binder);

        if (target.prototype) {
            Empty.prototype = target.prototype;
            bound.prototype = new Empty();
            // Clean up dangling references.
            Empty.prototype = null;
        }

        // TODO
        // 18. Set the [[Extensible]] internal property of F to true.

        // TODO
        // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
        // 20. Call the [[DefineOwnProperty]] internal method of F with
        //   arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
        //   thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
        //   false.
        // 21. Call the [[DefineOwnProperty]] internal method of F with
        //   arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
        //   [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
        //   and false.

        // TODO
        // NOTE Function objects created using Function.prototype.bind do not
        // have a prototype property or the [[Code]], [[FormalParameters]], and
        // [[Scope]] internal properties.
        // XXX can't delete prototype in pure-js.

        // 22. Return F.
        return bound;
    }
});

// _Please note: Shortcuts are defined after `Function.prototype.bind` as we
// us it in defining shortcuts.
var owns = call.bind(ObjectPrototype.hasOwnProperty);

// If JS engine supports accessors creating shortcuts.
var defineGetter;
var defineSetter;
var lookupGetter;
var lookupSetter;
var supportsAccessors;
if ((supportsAccessors = owns(ObjectPrototype, "__defineGetter__"))) {
    defineGetter = call.bind(ObjectPrototype.__defineGetter__);
    defineSetter = call.bind(ObjectPrototype.__defineSetter__);
    lookupGetter = call.bind(ObjectPrototype.__lookupGetter__);
    lookupSetter = call.bind(ObjectPrototype.__lookupSetter__);
}

//
// Array
// =====
//

// ES5 15.4.4.12
// http://es5.github.com/#x15.4.4.12
var spliceNoopReturnsEmptyArray = (function () {
    var a = [1, 2];
    var result = a.splice();
    return a.length === 2 && isArray(result) && result.length === 0;
}());
defineProperties(ArrayPrototype, {
    // Safari 5.0 bug where .splice() returns undefined
    splice: function splice(start, deleteCount) {
        if (arguments.length === 0) {
            return [];
        } else {
            return array_splice.apply(this, arguments);
        }
    }
}, spliceNoopReturnsEmptyArray);

var spliceWorksWithEmptyObject = (function () {
    var obj = {};
    ArrayPrototype.splice.call(obj, 0, 0, 1);
    return obj.length === 1;
}());
defineProperties(ArrayPrototype, {
    splice: function splice(start, deleteCount) {
        if (arguments.length === 0) { return []; }
        var args = arguments;
        this.length = Math.max(toInteger(this.length), 0);
        if (arguments.length > 0 && typeof deleteCount !== 'number') {
            args = array_slice.call(arguments);
            if (args.length < 2) {
                args.push(this.length - start);
            } else {
                args[1] = toInteger(deleteCount);
            }
        }
        return array_splice.apply(this, args);
    }
}, !spliceWorksWithEmptyObject);

// ES5 15.4.4.12
// http://es5.github.com/#x15.4.4.13
// Return len+argCount.
// [bugfix, ielt8]
// IE < 8 bug: [].unshift(0) === undefined but should be "1"
var hasUnshiftReturnValueBug = [].unshift(0) !== 1;
defineProperties(ArrayPrototype, {
    unshift: function () {
        array_unshift.apply(this, arguments);
        return this.length;
    }
}, hasUnshiftReturnValueBug);

// ES5 15.4.3.2
// http://es5.github.com/#x15.4.3.2
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
defineProperties(Array, { isArray: isArray });

// The IsCallable() check in the Array functions
// has been replaced with a strict check on the
// internal class of the object to trap cases where
// the provided function was actually a regular
// expression literal, which in V8 and
// JavaScriptCore is a typeof "function".  Only in
// V8 are regular expression literals permitted as
// reduce parameters, so it is desirable in the
// general case for the shim to match the more
// strict and common behavior of rejecting regular
// expressions.

// ES5 15.4.4.18
// http://es5.github.com/#x15.4.4.18
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach

// Check failure of by-index access of string characters (IE < 9)
// and failure of `0 in boxedString` (Rhino)
var boxedString = Object("a");
var splitString = boxedString[0] !== "a" || !(0 in boxedString);

var properlyBoxesContext = function properlyBoxed(method) {
    // Check node 0.6.21 bug where third parameter is not boxed
    var properlyBoxesNonStrict = true;
    var properlyBoxesStrict = true;
    if (method) {
        method.call('foo', function (_, __, context) {
            if (typeof context !== 'object') { properlyBoxesNonStrict = false; }
        });

        method.call([1], function () {
            'use strict';
            properlyBoxesStrict = typeof this === 'string';
        }, 'x');
    }
    return !!method && properlyBoxesNonStrict && properlyBoxesStrict;
};

defineProperties(ArrayPrototype, {
    forEach: function forEach(fun /*, thisp*/) {
        var object = toObject(this),
            self = splitString && isString(this) ? this.split('') : object,
            thisp = arguments[1],
            i = -1,
            length = self.length >>> 0;

        // If no callback function or if callback is not a callable function
        if (!isFunction(fun)) {
            throw new TypeError(); // TODO message
        }

        while (++i < length) {
            if (i in self) {
                // Invoke the callback function with call, passing arguments:
                // context, property value, property key, thisArg object
                // context
                fun.call(thisp, self[i], i, object);
            }
        }
    }
}, !properlyBoxesContext(ArrayPrototype.forEach));

// ES5 15.4.4.19
// http://es5.github.com/#x15.4.4.19
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
defineProperties(ArrayPrototype, {
    map: function map(fun /*, thisp*/) {
        var object = toObject(this),
            self = splitString && isString(this) ? this.split('') : object,
            length = self.length >>> 0,
            result = Array(length),
            thisp = arguments[1];

        // If no callback function or if callback is not a callable function
        if (!isFunction(fun)) {
            throw new TypeError(fun + " is not a function");
        }

        for (var i = 0; i < length; i++) {
            if (i in self) {
                result[i] = fun.call(thisp, self[i], i, object);
            }
        }
        return result;
    }
}, !properlyBoxesContext(ArrayPrototype.map));

// ES5 15.4.4.20
// http://es5.github.com/#x15.4.4.20
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
defineProperties(ArrayPrototype, {
    filter: function filter(fun /*, thisp */) {
        var object = toObject(this),
            self = splitString && isString(this) ? this.split('') : object,
            length = self.length >>> 0,
            result = [],
            value,
            thisp = arguments[1];

        // If no callback function or if callback is not a callable function
        if (!isFunction(fun)) {
            throw new TypeError(fun + " is not a function");
        }

        for (var i = 0; i < length; i++) {
            if (i in self) {
                value = self[i];
                if (fun.call(thisp, value, i, object)) {
                    result.push(value);
                }
            }
        }
        return result;
    }
}, !properlyBoxesContext(ArrayPrototype.filter));

// ES5 15.4.4.16
// http://es5.github.com/#x15.4.4.16
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
defineProperties(ArrayPrototype, {
    every: function every(fun /*, thisp */) {
        var object = toObject(this),
            self = splitString && isString(this) ? this.split('') : object,
            length = self.length >>> 0,
            thisp = arguments[1];

        // If no callback function or if callback is not a callable function
        if (!isFunction(fun)) {
            throw new TypeError(fun + " is not a function");
        }

        for (var i = 0; i < length; i++) {
            if (i in self && !fun.call(thisp, self[i], i, object)) {
                return false;
            }
        }
        return true;
    }
}, !properlyBoxesContext(ArrayPrototype.every));

// ES5 15.4.4.17
// http://es5.github.com/#x15.4.4.17
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
defineProperties(ArrayPrototype, {
    some: function some(fun /*, thisp */) {
        var object = toObject(this),
            self = splitString && isString(this) ? this.split('') : object,
            length = self.length >>> 0,
            thisp = arguments[1];

        // If no callback function or if callback is not a callable function
        if (!isFunction(fun)) {
            throw new TypeError(fun + " is not a function");
        }

        for (var i = 0; i < length; i++) {
            if (i in self && fun.call(thisp, self[i], i, object)) {
                return true;
            }
        }
        return false;
    }
}, !properlyBoxesContext(ArrayPrototype.some));

// ES5 15.4.4.21
// http://es5.github.com/#x15.4.4.21
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
var reduceCoercesToObject = false;
if (ArrayPrototype.reduce) {
    reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object';
}
defineProperties(ArrayPrototype, {
    reduce: function reduce(fun /*, initial*/) {
        var object = toObject(this),
            self = splitString && isString(this) ? this.split('') : object,
            length = self.length >>> 0;

        // If no callback function or if callback is not a callable function
        if (!isFunction(fun)) {
            throw new TypeError(fun + " is not a function");
        }

        // no value to return if no initial value and an empty array
        if (!length && arguments.length === 1) {
            throw new TypeError("reduce of empty array with no initial value");
        }

        var i = 0;
        var result;
        if (arguments.length >= 2) {
            result = arguments[1];
        } else {
            do {
                if (i in self) {
                    result = self[i++];
                    break;
                }

                // if array contains no values, no initial value to return
                if (++i >= length) {
                    throw new TypeError("reduce of empty array with no initial value");
                }
            } while (true);
        }

        for (; i < length; i++) {
            if (i in self) {
                result = fun.call(void 0, result, self[i], i, object);
            }
        }

        return result;
    }
}, !reduceCoercesToObject);

// ES5 15.4.4.22
// http://es5.github.com/#x15.4.4.22
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
var reduceRightCoercesToObject = false;
if (ArrayPrototype.reduceRight) {
    reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object';
}
defineProperties(ArrayPrototype, {
    reduceRight: function reduceRight(fun /*, initial*/) {
        var object = toObject(this),
            self = splitString && isString(this) ? this.split('') : object,
            length = self.length >>> 0;

        // If no callback function or if callback is not a callable function
        if (!isFunction(fun)) {
            throw new TypeError(fun + " is not a function");
        }

        // no value to return if no initial value, empty array
        if (!length && arguments.length === 1) {
            throw new TypeError("reduceRight of empty array with no initial value");
        }

        var result, i = length - 1;
        if (arguments.length >= 2) {
            result = arguments[1];
        } else {
            do {
                if (i in self) {
                    result = self[i--];
                    break;
                }

                // if array contains no values, no initial value to return
                if (--i < 0) {
                    throw new TypeError("reduceRight of empty array with no initial value");
                }
            } while (true);
        }

        if (i < 0) {
            return result;
        }

        do {
            if (i in self) {
                result = fun.call(void 0, result, self[i], i, object);
            }
        } while (i--);

        return result;
    }
}, !reduceRightCoercesToObject);

// ES5 15.4.4.14
// http://es5.github.com/#x15.4.4.14
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1;
defineProperties(ArrayPrototype, {
    indexOf: function indexOf(sought /*, fromIndex */ ) {
        var self = splitString && isString(this) ? this.split('') : toObject(this),
            length = self.length >>> 0;

        if (!length) {
            return -1;
        }

        var i = 0;
        if (arguments.length > 1) {
            i = toInteger(arguments[1]);
        }

        // handle negative indices
        i = i >= 0 ? i : Math.max(0, length + i);
        for (; i < length; i++) {
            if (i in self && self[i] === sought) {
                return i;
            }
        }
        return -1;
    }
}, hasFirefox2IndexOfBug);

// ES5 15.4.4.15
// http://es5.github.com/#x15.4.4.15
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
var hasFirefox2LastIndexOfBug = Array.prototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1;
defineProperties(ArrayPrototype, {
    lastIndexOf: function lastIndexOf(sought /*, fromIndex */) {
        var self = splitString && isString(this) ? this.split('') : toObject(this),
            length = self.length >>> 0;

        if (!length) {
            return -1;
        }
        var i = length - 1;
        if (arguments.length > 1) {
            i = Math.min(i, toInteger(arguments[1]));
        }
        // handle negative indices
        i = i >= 0 ? i : length - Math.abs(i);
        for (; i >= 0; i--) {
            if (i in self && sought === self[i]) {
                return i;
            }
        }
        return -1;
    }
}, hasFirefox2LastIndexOfBug);

//
// Object
// ======
//

// ES5 15.2.3.14
// http://es5.github.com/#x15.2.3.14

// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
    hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
    dontEnums = [
        "toString",
        "toLocaleString",
        "valueOf",
        "hasOwnProperty",
        "isPrototypeOf",
        "propertyIsEnumerable",
        "constructor"
    ],
    dontEnumsLength = dontEnums.length;

defineProperties(Object, {
    keys: function keys(object) {
        var isFn = isFunction(object),
            isArgs = isArguments(object),
            isObject = object !== null && typeof object === 'object',
            isStr = isObject && isString(object);

        if (!isObject && !isFn && !isArgs) {
            throw new TypeError("Object.keys called on a non-object");
        }

        var theKeys = [];
        var skipProto = hasProtoEnumBug && isFn;
        if (isStr || isArgs) {
            for (var i = 0; i < object.length; ++i) {
                theKeys.push(String(i));
            }
        } else {
            for (var name in object) {
                if (!(skipProto && name === 'prototype') && owns(object, name)) {
                    theKeys.push(String(name));
                }
            }
        }

        if (hasDontEnumBug) {
            var ctor = object.constructor,
                skipConstructor = ctor && ctor.prototype === object;
            for (var j = 0; j < dontEnumsLength; j++) {
                var dontEnum = dontEnums[j];
                if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) {
                    theKeys.push(dontEnum);
                }
            }
        }
        return theKeys;
    }
});

var keysWorksWithArguments = Object.keys && (function () {
    // Safari 5.0 bug
    return Object.keys(arguments).length === 2;
}(1, 2));
var originalKeys = Object.keys;
defineProperties(Object, {
    keys: function keys(object) {
        if (isArguments(object)) {
            return originalKeys(ArrayPrototype.slice.call(object));
        } else {
            return originalKeys(object);
        }
    }
}, !keysWorksWithArguments);

//
// Date
// ====
//

// ES5 15.9.5.43
// http://es5.github.com/#x15.9.5.43
// This function returns a String value represent the instance in time
// represented by this Date object. The format of the String is the Date Time
// string format defined in 15.9.1.15. All fields are present in the String.
// The time zone is always UTC, denoted by the suffix Z. If the time value of
// this object is not a finite Number a RangeError exception is thrown.
var negativeDate = -62198755200000;
var negativeYearString = "-000001";
var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1;

defineProperties(Date.prototype, {
    toISOString: function toISOString() {
        var result, length, value, year, month;
        if (!isFinite(this)) {
            throw new RangeError("Date.prototype.toISOString called on non-finite value.");
        }

        year = this.getUTCFullYear();

        month = this.getUTCMonth();
        // see https://github.com/es-shims/es5-shim/issues/111
        year += Math.floor(month / 12);
        month = (month % 12 + 12) % 12;

        // the date time string format is specified in 15.9.1.15.
        result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
        year = (
            (year < 0 ? "-" : (year > 9999 ? "+" : "")) +
            ("00000" + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6)
        );

        length = result.length;
        while (length--) {
            value = result[length];
            // pad months, days, hours, minutes, and seconds to have two
            // digits.
            if (value < 10) {
                result[length] = "0" + value;
            }
        }
        // pad milliseconds to have three digits.
        return (
            year + "-" + result.slice(0, 2).join("-") +
            "T" + result.slice(2).join(":") + "." +
            ("000" + this.getUTCMilliseconds()).slice(-3) + "Z"
        );
    }
}, hasNegativeDateBug);


// ES5 15.9.5.44
// http://es5.github.com/#x15.9.5.44
// This function provides a String representation of a Date object for use by
// JSON.stringify (15.12.3).
var dateToJSONIsSupported = false;
try {
    dateToJSONIsSupported = (
        Date.prototype.toJSON &&
        new Date(NaN).toJSON() === null &&
        new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 &&
        Date.prototype.toJSON.call({ // generic
            toISOString: function () {
                return true;
            }
        })
    );
} catch (e) {
}
if (!dateToJSONIsSupported) {
    Date.prototype.toJSON = function toJSON(key) {
        // When the toJSON method is called with argument key, the following
        // steps are taken:

        // 1.  Let O be the result of calling ToObject, giving it the this
        // value as its argument.
        // 2. Let tv be toPrimitive(O, hint Number).
        var o = Object(this),
            tv = toPrimitive(o),
            toISO;
        // 3. If tv is a Number and is not finite, return null.
        if (typeof tv === "number" && !isFinite(tv)) {
            return null;
        }
        // 4. Let toISO be the result of calling the [[Get]] internal method of
        // O with argument "toISOString".
        toISO = o.toISOString;
        // 5. If IsCallable(toISO) is false, throw a TypeError exception.
        if (typeof toISO !== "function") {
            throw new TypeError("toISOString property is not callable");
        }
        // 6. Return the result of calling the [[Call]] internal method of
        //  toISO with O as the this value and an empty argument list.
        return toISO.call(o);

        // NOTE 1 The argument is ignored.

        // NOTE 2 The toJSON function is intentionally generic; it does not
        // require that its this value be a Date object. Therefore, it can be
        // transferred to other kinds of objects for use as a method. However,
        // it does require that any such object have a toISOString method. An
        // object is free to use the argument key to filter its
        // stringification.
    };
}

// ES5 15.9.4.2
// http://es5.github.com/#x15.9.4.2
// based on work shared by Daniel Friesen (dantman)
// http://gist.github.com/303249
var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15;
var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z'));
var doesNotParseY2KNewYear = isNaN(Date.parse("2000-01-01T00:00:00.000Z"));
if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) {
    // XXX global assignment won't work in embeddings that use
    // an alternate object for the context.
    Date = (function (NativeDate) {

        // Date.length === 7
        function Date(Y, M, D, h, m, s, ms) {
            var length = arguments.length;
            if (this instanceof NativeDate) {
                var date = length === 1 && String(Y) === Y ? // isString(Y)
                    // We explicitly pass it through parse:
                    new NativeDate(Date.parse(Y)) :
                    // We have to manually make calls depending on argument
                    // length here
                    length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
                    length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
                    length >= 5 ? new NativeDate(Y, M, D, h, m) :
                    length >= 4 ? new NativeDate(Y, M, D, h) :
                    length >= 3 ? new NativeDate(Y, M, D) :
                    length >= 2 ? new NativeDate(Y, M) :
                    length >= 1 ? new NativeDate(Y) :
                                  new NativeDate();
                // Prevent mixups with unfixed Date object
                date.constructor = Date;
                return date;
            }
            return NativeDate.apply(this, arguments);
        }

        // 15.9.1.15 Date Time String Format.
        var isoDateExpression = new RegExp("^" +
            "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign +
                                      // 6-digit extended year
            "(?:-(\\d{2})" + // optional month capture
            "(?:-(\\d{2})" + // optional day capture
            "(?:" + // capture hours:minutes:seconds.milliseconds
                "T(\\d{2})" + // hours capture
                ":(\\d{2})" + // minutes capture
                "(?:" + // optional :seconds.milliseconds
                    ":(\\d{2})" + // seconds capture
                    "(?:(\\.\\d{1,}))?" + // milliseconds capture
                ")?" +
            "(" + // capture UTC offset component
                "Z|" + // UTC capture
                "(?:" + // offset specifier +/-hours:minutes
                    "([-+])" + // sign capture
                    "(\\d{2})" + // hours offset capture
                    ":(\\d{2})" + // minutes offset capture
                ")" +
            ")?)?)?)?" +
        "$");

        var months = [
            0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
        ];

        function dayFromMonth(year, month) {
            var t = month > 1 ? 1 : 0;
            return (
                months[month] +
                Math.floor((year - 1969 + t) / 4) -
                Math.floor((year - 1901 + t) / 100) +
                Math.floor((year - 1601 + t) / 400) +
                365 * (year - 1970)
            );
        }

        function toUTC(t) {
            return Number(new NativeDate(1970, 0, 1, 0, 0, 0, t));
        }

        // Copy any custom methods a 3rd party library may have added
        for (var key in NativeDate) {
            Date[key] = NativeDate[key];
        }

        // Copy "native" methods explicitly; they may be non-enumerable
        Date.now = NativeDate.now;
        Date.UTC = NativeDate.UTC;
        Date.prototype = NativeDate.prototype;
        Date.prototype.constructor = Date;

        // Upgrade Date.parse to handle simplified ISO 8601 strings
        Date.parse = function parse(string) {
            var match = isoDateExpression.exec(string);
            if (match) {
                // parse months, days, hours, minutes, seconds, and milliseconds
                // provide default values if necessary
                // parse the UTC offset component
                var year = Number(match[1]),
                    month = Number(match[2] || 1) - 1,
                    day = Number(match[3] || 1) - 1,
                    hour = Number(match[4] || 0),
                    minute = Number(match[5] || 0),
                    second = Number(match[6] || 0),
                    millisecond = Math.floor(Number(match[7] || 0) * 1000),
                    // When time zone is missed, local offset should be used
                    // (ES 5.1 bug)
                    // see https://bugs.ecmascript.org/show_bug.cgi?id=112
                    isLocalTime = Boolean(match[4] && !match[8]),
                    signOffset = match[9] === "-" ? 1 : -1,
                    hourOffset = Number(match[10] || 0),
                    minuteOffset = Number(match[11] || 0),
                    result;
                if (
                    hour < (
                        minute > 0 || second > 0 || millisecond > 0 ?
                        24 : 25
                    ) &&
                    minute < 60 && second < 60 && millisecond < 1000 &&
                    month > -1 && month < 12 && hourOffset < 24 &&
                    minuteOffset < 60 && // detect invalid offsets
                    day > -1 &&
                    day < (
                        dayFromMonth(year, month + 1) -
                        dayFromMonth(year, month)
                    )
                ) {
                    result = (
                        (dayFromMonth(year, month) + day) * 24 +
                        hour +
                        hourOffset * signOffset
                    ) * 60;
                    result = (
                        (result + minute + minuteOffset * signOffset) * 60 +
                        second
                    ) * 1000 + millisecond;
                    if (isLocalTime) {
                        result = toUTC(result);
                    }
                    if (-8.64e15 <= result && result <= 8.64e15) {
                        return result;
                    }
                }
                return NaN;
            }
            return NativeDate.parse.apply(this, arguments);
        };

        return Date;
    })(Date);
}

// ES5 15.9.4.4
// http://es5.github.com/#x15.9.4.4
if (!Date.now) {
    Date.now = function now() {
        return new Date().getTime();
    };
}


//
// Number
// ======
//

// ES5.1 15.7.4.5
// http://es5.github.com/#x15.7.4.5
var hasToFixedBugs = NumberPrototype.toFixed && (
  (0.00008).toFixed(3) !== '0.000'
  || (0.9).toFixed(0) !== '1'
  || (1.255).toFixed(2) !== '1.25'
  || (1000000000000000128).toFixed(0) !== "1000000000000000128"
);

var toFixedHelpers = {
  base: 1e7,
  size: 6,
  data: [0, 0, 0, 0, 0, 0],
  multiply: function multiply(n, c) {
      var i = -1;
      while (++i < toFixedHelpers.size) {
          c += n * toFixedHelpers.data[i];
          toFixedHelpers.data[i] = c % toFixedHelpers.base;
          c = Math.floor(c / toFixedHelpers.base);
      }
  },
  divide: function divide(n) {
      var i = toFixedHelpers.size, c = 0;
      while (--i >= 0) {
          c += toFixedHelpers.data[i];
          toFixedHelpers.data[i] = Math.floor(c / n);
          c = (c % n) * toFixedHelpers.base;
      }
  },
  numToString: function numToString() {
      var i = toFixedHelpers.size;
      var s = '';
      while (--i >= 0) {
          if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) {
              var t = String(toFixedHelpers.data[i]);
              if (s === '') {
                  s = t;
              } else {
                  s += '0000000'.slice(0, 7 - t.length) + t;
              }
          }
      }
      return s;
  },
  pow: function pow(x, n, acc) {
      return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc)));
  },
  log: function log(x) {
      var n = 0;
      while (x >= 4096) {
          n += 12;
          x /= 4096;
      }
      while (x >= 2) {
          n += 1;
          x /= 2;
      }
      return n;
  }
};

defineProperties(NumberPrototype, {
    toFixed: function toFixed(fractionDigits) {
        var f, x, s, m, e, z, j, k;

        // Test for NaN and round fractionDigits down
        f = Number(fractionDigits);
        f = f !== f ? 0 : Math.floor(f);

        if (f < 0 || f > 20) {
            throw new RangeError("Number.toFixed called with invalid number of decimals");
        }

        x = Number(this);

        // Test for NaN
        if (x !== x) {
            return "NaN";
        }

        // If it is too big or small, return the string value of the number
        if (x <= -1e21 || x >= 1e21) {
            return String(x);
        }

        s = "";

        if (x < 0) {
            s = "-";
            x = -x;
        }

        m = "0";

        if (x > 1e-21) {
            // 1e-21 < x < 1e21
            // -70 < log2(x) < 70
            e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69;
            z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1));
            z *= 0x10000000000000; // Math.pow(2, 52);
            e = 52 - e;

            // -18 < e < 122
            // x = z / 2 ^ e
            if (e > 0) {
                toFixedHelpers.multiply(0, z);
                j = f;

                while (j >= 7) {
                    toFixedHelpers.multiply(1e7, 0);
                    j -= 7;
                }

                toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0);
                j = e - 1;

                while (j >= 23) {
                    toFixedHelpers.divide(1 << 23);
                    j -= 23;
                }

                toFixedHelpers.divide(1 << j);
                toFixedHelpers.multiply(1, 1);
                toFixedHelpers.divide(2);
                m = toFixedHelpers.numToString();
            } else {
                toFixedHelpers.multiply(0, z);
                toFixedHelpers.multiply(1 << (-e), 0);
                m = toFixedHelpers.numToString() + '0.00000000000000000000'.slice(2, 2 + f);
            }
        }

        if (f > 0) {
            k = m.length;

            if (k <= f) {
                m = s + '0.0000000000000000000'.slice(0, f - k + 2) + m;
            } else {
                m = s + m.slice(0, k - f) + '.' + m.slice(k - f);
            }
        } else {
            m = s + m;
        }

        return m;
    }
}, hasToFixedBugs);


//
// String
// ======
//

// ES5 15.5.4.14
// http://es5.github.com/#x15.5.4.14

// [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers]
// Many browsers do not split properly with regular expressions or they
// do not perform the split correctly under obscure conditions.
// See http://blog.stevenlevithan.com/archives/cross-browser-split
// I've tested in many browsers and this seems to cover the deviant ones:
//    'ab'.split(/(?:ab)*/) should be ["", ""], not [""]
//    '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""]
//    'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not
//       [undefined, "t", undefined, "e", ...]
//    ''.split(/.?/) should be [], not [""]
//    '.'.split(/()()/) should be ["."], not ["", "", "."]

var string_split = StringPrototype.split;
if (
    'ab'.split(/(?:ab)*/).length !== 2 ||
    '.'.split(/(.?)(.?)/).length !== 4 ||
    'tesst'.split(/(s)*/)[1] === "t" ||
    'test'.split(/(?:)/, -1).length !== 4 ||
    ''.split(/.?/).length ||
    '.'.split(/()()/).length > 1
) {
    (function () {
        var compliantExecNpcg = /()??/.exec("")[1] === void 0; // NPCG: nonparticipating capturing group

        StringPrototype.split = function (separator, limit) {
            var string = this;
            if (separator === void 0 && limit === 0) {
                return [];
            }

            // If `separator` is not a regex, use native split
            if (_toString.call(separator) !== "[object RegExp]") {
                return string_split.call(this, separator, limit);
            }

            var output = [],
                flags = (separator.ignoreCase ? "i" : "") +
                        (separator.multiline  ? "m" : "") +
                        (separator.extended   ? "x" : "") + // Proposed for ES6
                        (separator.sticky     ? "y" : ""), // Firefox 3+
                lastLastIndex = 0,
                // Make `global` and avoid `lastIndex` issues by working with a copy
                separator2, match, lastIndex, lastLength;
            separator = new RegExp(separator.source, flags + "g");
            string += ""; // Type-convert
            if (!compliantExecNpcg) {
                // Doesn't need flags gy, but they don't hurt
                separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
            }
            /* Values for `limit`, per the spec:
             * If undefined: 4294967295 // Math.pow(2, 32) - 1
             * If 0, Infinity, or NaN: 0
             * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
             * If negative number: 4294967296 - Math.floor(Math.abs(limit))
             * If other: Type-convert, then use the above rules
             */
            limit = limit === void 0 ?
                -1 >>> 0 : // Math.pow(2, 32) - 1
                ToUint32(limit);
            while (match = separator.exec(string)) {
                // `separator.lastIndex` is not reliable cross-browser
                lastIndex = match.index + match[0].length;
                if (lastIndex > lastLastIndex) {
                    output.push(string.slice(lastLastIndex, match.index));
                    // Fix browsers whose `exec` methods don't consistently return `undefined` for
                    // nonparticipating capturing groups
                    if (!compliantExecNpcg && match.length > 1) {
                        match[0].replace(separator2, function () {
                            for (var i = 1; i < arguments.length - 2; i++) {
                                if (arguments[i] === void 0) {
                                    match[i] = void 0;
                                }
                            }
                        });
                    }
                    if (match.length > 1 && match.index < string.length) {
                        ArrayPrototype.push.apply(output, match.slice(1));
                    }
                    lastLength = match[0].length;
                    lastLastIndex = lastIndex;
                    if (output.length >= limit) {
                        break;
                    }
                }
                if (separator.lastIndex === match.index) {
                    separator.lastIndex++; // Avoid an infinite loop
                }
            }
            if (lastLastIndex === string.length) {
                if (lastLength || !separator.test("")) {
                    output.push("");
                }
            } else {
                output.push(string.slice(lastLastIndex));
            }
            return output.length > limit ? output.slice(0, limit) : output;
        };
    }());

// [bugfix, chrome]
// If separator is undefined, then the result array contains just one String,
// which is the this value (converted to a String). If limit is not undefined,
// then the output array is truncated so that it contains no more than limit
// elements.
// "0".split(undefined, 0) -> []
} else if ("0".split(void 0, 0).length) {
    StringPrototype.split = function split(separator, limit) {
        if (separator === void 0 && limit === 0) { return []; }
        return string_split.call(this, separator, limit);
    };
}

var str_replace = StringPrototype.replace;
var replaceReportsGroupsCorrectly = (function () {
    var groups = [];
    'x'.replace(/x(.)?/g, function (match, group) {
        groups.push(group);
    });
    return groups.length === 1 && typeof groups[0] === 'undefined';
}());

if (!replaceReportsGroupsCorrectly) {
    StringPrototype.replace = function replace(searchValue, replaceValue) {
        var isFn = isFunction(replaceValue);
        var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source);
        if (!isFn || !hasCapturingGroups) {
            return str_replace.call(this, searchValue, replaceValue);
        } else {
            var wrappedReplaceValue = function (match) {
                var length = arguments.length;
                var originalLastIndex = searchValue.lastIndex;
                searchValue.lastIndex = 0;
                var args = searchValue.exec(match) || [];
                searchValue.lastIndex = originalLastIndex;
                args.push(arguments[length - 2], arguments[length - 1]);
                return replaceValue.apply(this, args);
            };
            return str_replace.call(this, searchValue, wrappedReplaceValue);
        }
    };
}

// ECMA-262, 3rd B.2.3
// Not an ECMAScript standard, although ECMAScript 3rd Edition has a
// non-normative section suggesting uniform semantics and it should be
// normalized across all browsers
// [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE
var string_substr = StringPrototype.substr;
var hasNegativeSubstrBug = "".substr && "0b".substr(-1) !== "b";
defineProperties(StringPrototype, {
    substr: function substr(start, length) {
        return string_substr.call(
            this,
            start < 0 ? ((start = this.length + start) < 0 ? 0 : start) : start,
            length
        );
    }
}, hasNegativeSubstrBug);

// ES5 15.5.4.20
// whitespace from: http://es5.github.io/#x15.5.4.20
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
    "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
    "\u2029\uFEFF";
var zeroWidth = '\u200b';
var wsRegexChars = "[" + ws + "]";
var trimBeginRegexp = new RegExp("^" + wsRegexChars + wsRegexChars + "*");
var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + "*$");
var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim());
defineProperties(StringPrototype, {
    // http://blog.stevenlevithan.com/archives/faster-trim-javascript
    // http://perfectionkills.com/whitespace-deviations/
    trim: function trim() {
        if (this === void 0 || this === null) {
            throw new TypeError("can't convert " + this + " to object");
        }
        return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
    }
}, hasTrimWhitespaceBug);

// ES-5 15.1.2.2
if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) {
    parseInt = (function (origParseInt) {
        var hexRegex = /^0[xX]/;
        return function parseIntES5(str, radix) {
            str = String(str).trim();
            if (!Number(radix)) {
                radix = hexRegex.test(str) ? 16 : 10;
            }
            return origParseInt(str, radix);
        };
    }(parseInt));
}

}));
/*!
 * https://github.com/es-shims/es5-shim
 * @license es5-shim Copyright 2009-2014 by contributors, MIT License
 * see https://github.com/es-shims/es5-shim/blob/master/LICENSE
 */

// vim: ts=4 sts=4 sw=4 expandtab

//Add semicolon to prevent IIFE from being passed as argument to concated code.
;

// UMD (Universal Module Definition)
// see https://github.com/umdjs/umd/blob/master/returnExports.js
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(factory);
    } else if (typeof exports === 'object') {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like enviroments that support module.exports,
        // like Node.
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        root.returnExports = factory();
  }
}(this, function () {

var call = Function.prototype.call;
var prototypeOfObject = Object.prototype;
var owns = call.bind(prototypeOfObject.hasOwnProperty);

// If JS engine supports accessors creating shortcuts.
var defineGetter;
var defineSetter;
var lookupGetter;
var lookupSetter;
var supportsAccessors = owns(prototypeOfObject, "__defineGetter__");
if (supportsAccessors) {
    defineGetter = call.bind(prototypeOfObject.__defineGetter__);
    defineSetter = call.bind(prototypeOfObject.__defineSetter__);
    lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
    lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
}

// ES5 15.2.3.2
// http://es5.github.com/#x15.2.3.2
if (!Object.getPrototypeOf) {
    // https://github.com/es-shims/es5-shim/issues#issue/2
    // http://ejohn.org/blog/objectgetprototypeof/
    // recommended by fschaefer on github
    //
    // sure, and webreflection says ^_^
    // ... this will nerever possibly return null
    // ... Opera Mini breaks here with infinite loops
    Object.getPrototypeOf = function getPrototypeOf(object) {
        var proto = object.__proto__;
        if (proto || proto === null) {
            return proto;
        } else if (object.constructor) {
            return object.constructor.prototype;
        } else {
            return prototypeOfObject;
        }
    };
}

//ES5 15.2.3.3
//http://es5.github.com/#x15.2.3.3

function doesGetOwnPropertyDescriptorWork(object) {
    try {
        object.sentinel = 0;
        return Object.getOwnPropertyDescriptor(
                object,
                "sentinel"
        ).value === 0;
    } catch (exception) {
        // returns falsy
    }
}

//check whether getOwnPropertyDescriptor works if it's given. Otherwise,
//shim partially.
if (Object.defineProperty) {
    var getOwnPropertyDescriptorWorksOnObject = doesGetOwnPropertyDescriptorWork({});
    var getOwnPropertyDescriptorWorksOnDom = typeof document === "undefined" ||
    doesGetOwnPropertyDescriptorWork(document.createElement("div"));
    if (!getOwnPropertyDescriptorWorksOnDom || !getOwnPropertyDescriptorWorksOnObject) {
        var getOwnPropertyDescriptorFallback = Object.getOwnPropertyDescriptor;
    }
}

if (!Object.getOwnPropertyDescriptor || getOwnPropertyDescriptorFallback) {
    var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a non-object: ";

    Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
        if ((typeof object !== "object" && typeof object !== "function") || object === null) {
            throw new TypeError(ERR_NON_OBJECT + object);
        }

        // make a valiant attempt to use the real getOwnPropertyDescriptor
        // for I8's DOM elements.
        if (getOwnPropertyDescriptorFallback) {
            try {
                return getOwnPropertyDescriptorFallback.call(Object, object, property);
            } catch (exception) {
                // try the shim if the real one doesn't work
            }
        }

        // If object does not owns property return undefined immediately.
        if (!owns(object, property)) {
            return;
        }

        // If object has a property then it's for sure both `enumerable` and
        // `configurable`.
        var descriptor =  { enumerable: true, configurable: true };

        // If JS engine supports accessor properties then property may be a
        // getter or setter.
        if (supportsAccessors) {
            // Unfortunately `__lookupGetter__` will return a getter even
            // if object has own non getter property along with a same named
            // inherited getter. To avoid misbehavior we temporary remove
            // `__proto__` so that `__lookupGetter__` will return getter only
            // if it's owned by an object.
            var prototype = object.__proto__;
            var notPrototypeOfObject = object !== prototypeOfObject;
            // avoid recursion problem, breaking in Opera Mini when
            // Object.getOwnPropertyDescriptor(Object.prototype, 'toString')
            // or any other Object.prototype accessor
            if (notPrototypeOfObject) {
                object.__proto__ = prototypeOfObject;
            }

            var getter = lookupGetter(object, property);
            var setter = lookupSetter(object, property);

            if (notPrototypeOfObject) {
                // Once we have getter and setter we can put values back.
                object.__proto__ = prototype;
            }

            if (getter || setter) {
                if (getter) {
                    descriptor.get = getter;
                }
                if (setter) {
                    descriptor.set = setter;
                }
                // If it was accessor property we're done and return here
                // in order to avoid adding `value` to the descriptor.
                return descriptor;
            }
        }

        // If we got this far we know that object has an own property that is
        // not an accessor so we set it as a value and return descriptor.
        descriptor.value = object[property];
        descriptor.writable = true;
        return descriptor;
    };
}

// ES5 15.2.3.4
// http://es5.github.com/#x15.2.3.4
if (!Object.getOwnPropertyNames) {
    Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
        return Object.keys(object);
    };
}

// ES5 15.2.3.5
// http://es5.github.com/#x15.2.3.5
if (!Object.create) {

    // Contributed by Brandon Benvie, October, 2012
    var createEmpty;
    var supportsProto = !({__proto__:null} instanceof Object);
                        // the following produces false positives
                        // in Opera Mini => not a reliable check
                        // Object.prototype.__proto__ === null
    if (supportsProto || typeof document === 'undefined') {
        createEmpty = function () {
            return { "__proto__": null };
        };
    } else {
        // In old IE __proto__ can't be used to manually set `null`, nor does
        // any other method exist to make an object that inherits from nothing,
        // aside from Object.prototype itself. Instead, create a new global
        // object and *steal* its Object.prototype and strip it bare. This is
        // used as the prototype to create nullary objects.
        createEmpty = function () {
            var iframe = document.createElement('iframe');
            var parent = document.body || document.documentElement;
            iframe.style.display = 'none';
            parent.appendChild(iframe);
            iframe.src = 'javascript:';
            var empty = iframe.contentWindow.Object.prototype;
            parent.removeChild(iframe);
            iframe = null;
            delete empty.constructor;
            delete empty.hasOwnProperty;
            delete empty.propertyIsEnumerable;
            delete empty.isPrototypeOf;
            delete empty.toLocaleString;
            delete empty.toString;
            delete empty.valueOf;
            empty.__proto__ = null;

            function Empty() {}
            Empty.prototype = empty;
            // short-circuit future calls
            createEmpty = function () {
                return new Empty();
            };
            return new Empty();
        };
    }

    Object.create = function create(prototype, properties) {

        var object;
        function Type() {}  // An empty constructor.

        if (prototype === null) {
            object = createEmpty();
        } else {
            if (typeof prototype !== "object" && typeof prototype !== "function") {
                // In the native implementation `parent` can be `null`
                // OR *any* `instanceof Object`  (Object|Function|Array|RegExp|etc)
                // Use `typeof` tho, b/c in old IE, DOM elements are not `instanceof Object`
                // like they are in modern browsers. Using `Object.create` on DOM elements
                // is...err...probably inappropriate, but the native version allows for it.
                throw new TypeError("Object prototype may only be an Object or null"); // same msg as Chrome
            }
            Type.prototype = prototype;
            object = new Type();
            // IE has no built-in implementation of `Object.getPrototypeOf`
            // neither `__proto__`, but this manually setting `__proto__` will
            // guarantee that `Object.getPrototypeOf` will work as expected with
            // objects created using `Object.create`
            object.__proto__ = prototype;
        }

        if (properties !== void 0) {
            Object.defineProperties(object, properties);
        }

        return object;
    };
}

// ES5 15.2.3.6
// http://es5.github.com/#x15.2.3.6

// Patch for WebKit and IE8 standard mode
// Designed by hax <hax.github.com>
// related issue: https://github.com/es-shims/es5-shim/issues#issue/5
// IE8 Reference:
//     http://msdn.microsoft.com/en-us/library/dd282900.aspx
//     http://msdn.microsoft.com/en-us/library/dd229916.aspx
// WebKit Bugs:
//     https://bugs.webkit.org/show_bug.cgi?id=36423

function doesDefinePropertyWork(object) {
    try {
        Object.defineProperty(object, "sentinel", {});
        return "sentinel" in object;
    } catch (exception) {
        // returns falsy
    }
}

// check whether defineProperty works if it's given. Otherwise,
// shim partially.
if (Object.defineProperty) {
    var definePropertyWorksOnObject = doesDefinePropertyWork({});
    var definePropertyWorksOnDom = typeof document === "undefined" ||
        doesDefinePropertyWork(document.createElement("div"));
    if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
        var definePropertyFallback = Object.defineProperty,
            definePropertiesFallback = Object.defineProperties;
    }
}

if (!Object.defineProperty || definePropertyFallback) {
    var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
    var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: ";
    var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
                                      "on this javascript engine";

    Object.defineProperty = function defineProperty(object, property, descriptor) {
        if ((typeof object !== "object" && typeof object !== "function") || object === null) {
            throw new TypeError(ERR_NON_OBJECT_TARGET + object);
        }
        if ((typeof descriptor !== "object" && typeof descriptor !== "function") || descriptor === null) {
            throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
        }
        // make a valiant attempt to use the real defineProperty
        // for I8's DOM elements.
        if (definePropertyFallback) {
            try {
                return definePropertyFallback.call(Object, object, property, descriptor);
            } catch (exception) {
                // try the shim if the real one doesn't work
            }
        }

        // If it's a data property.
        if (owns(descriptor, "value")) {
            // fail silently if "writable", "enumerable", or "configurable"
            // are requested but not supported
            /*
            // alternate approach:
            if ( // can't implement these features; allow false but not true
                !(owns(descriptor, "writable") ? descriptor.writable : true) ||
                !(owns(descriptor, "enumerable") ? descriptor.enumerable : true) ||
                !(owns(descriptor, "configurable") ? descriptor.configurable : true)
            )
                throw new RangeError(
                    "This implementation of Object.defineProperty does not " +
                    "support configurable, enumerable, or writable."
                );
            */

            if (supportsAccessors && (lookupGetter(object, property) ||
                                      lookupSetter(object, property)))
            {
                // As accessors are supported only on engines implementing
                // `__proto__` we can safely override `__proto__` while defining
                // a property to make sure that we don't hit an inherited
                // accessor.
                var prototype = object.__proto__;
                object.__proto__ = prototypeOfObject;
                // Deleting a property anyway since getter / setter may be
                // defined on object itself.
                delete object[property];
                object[property] = descriptor.value;
                // Setting original `__proto__` back now.
                object.__proto__ = prototype;
            } else {
                object[property] = descriptor.value;
            }
        } else {
            if (!supportsAccessors) {
                throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
            }
            // If we got that far then getters and setters can be defined !!
            if (owns(descriptor, "get")) {
                defineGetter(object, property, descriptor.get);
            }
            if (owns(descriptor, "set")) {
                defineSetter(object, property, descriptor.set);
            }
        }
        return object;
    };
}

// ES5 15.2.3.7
// http://es5.github.com/#x15.2.3.7
if (!Object.defineProperties || definePropertiesFallback) {
    Object.defineProperties = function defineProperties(object, properties) {
        // make a valiant attempt to use the real defineProperties
        if (definePropertiesFallback) {
            try {
                return definePropertiesFallback.call(Object, object, properties);
            } catch (exception) {
                // try the shim if the real one doesn't work
            }
        }

        for (var property in properties) {
            if (owns(properties, property) && property !== "__proto__") {
                Object.defineProperty(object, property, properties[property]);
            }
        }
        return object;
    };
}

// ES5 15.2.3.8
// http://es5.github.com/#x15.2.3.8
if (!Object.seal) {
    Object.seal = function seal(object) {
        // this is misleading and breaks feature-detection, but
        // allows "securable" code to "gracefully" degrade to working
        // but insecure code.
        return object;
    };
}

// ES5 15.2.3.9
// http://es5.github.com/#x15.2.3.9
if (!Object.freeze) {
    Object.freeze = function freeze(object) {
        // this is misleading and breaks feature-detection, but
        // allows "securable" code to "gracefully" degrade to working
        // but insecure code.
        return object;
    };
}

// detect a Rhino bug and patch it
try {
    Object.freeze(function () {});
} catch (exception) {
    Object.freeze = (function freeze(freezeObject) {
        return function freeze(object) {
            if (typeof object === "function") {
                return object;
            } else {
                return freezeObject(object);
            }
        };
    })(Object.freeze);
}

// ES5 15.2.3.10
// http://es5.github.com/#x15.2.3.10
if (!Object.preventExtensions) {
    Object.preventExtensions = function preventExtensions(object) {
        // this is misleading and breaks feature-detection, but
        // allows "securable" code to "gracefully" degrade to working
        // but insecure code.
        return object;
    };
}

// ES5 15.2.3.11
// http://es5.github.com/#x15.2.3.11
if (!Object.isSealed) {
    Object.isSealed = function isSealed(object) {
        return false;
    };
}

// ES5 15.2.3.12
// http://es5.github.com/#x15.2.3.12
if (!Object.isFrozen) {
    Object.isFrozen = function isFrozen(object) {
        return false;
    };
}

// ES5 15.2.3.13
// http://es5.github.com/#x15.2.3.13
if (!Object.isExtensible) {
    Object.isExtensible = function isExtensible(object) {
        // 1. If Type(O) is not Object throw a TypeError exception.
        if (Object(object) !== object) {
            throw new TypeError(); // TODO message
        }
        // 2. Return the Boolean value of the [[Extensible]] internal property of O.
        var name = '';
        while (owns(object, name)) {
            name += '?';
        }
        object[name] = true;
        var returnValue = owns(object, name);
        delete object[name];
        return returnValue;
    };
}

}));

/*!
 * Shim for MutationObserver interface
 * Author: Graeme Yeates (github.com/megawac)
 * Repository: https://github.com/megawac/MutationObserver.js
 * License: WTFPL V2, 2004 (wtfpl.net).
 * Though credit and staring the repo will make me feel pretty, you can modify and redistribute as you please.
 * Attempts to follow spec (http://www.w3.org/TR/dom/#mutation-observers) as closely as possible for native javascript
 * See https://github.com/WebKit/webkit/blob/master/Source/WebCore/dom/MutationObserver.cpp for current webkit source c++ implementation
 */

/**
 * prefix bugs:
    -https://bugs.webkit.org/show_bug.cgi?id=85161
    -https://bugzilla.mozilla.org/show_bug.cgi?id=749920
*/
this.MutationObserver = this.MutationObserver || this.WebKitMutationObserver || (function(undefined) {
    "use strict";
    /**
     * @param {function(Array.<MutationRecord>, MutationObserver)} listener
     * @constructor
     */
    function MutationObserver(listener) {
        /**
         * @type {Array.<Object>}
         * @private
         */
        this._watched = [];
        /** @private */
        this._listener = listener;
    }

    /**
     * Start a recursive timeout function to check all items being observed for mutations
     * @type {MutationObserver} observer
     * @private
     */
    function startMutationChecker(observer) {
        (function check() {
            var mutations = observer.takeRecords();

            if (mutations.length) { //fire away
                //calling the listener with context is not spec but currently consistent with FF and WebKit
                observer._listener(mutations, observer);
            }
            /** @private */
            observer._timeout = setTimeout(check, MutationObserver._period);
        })();
    }

    /**
     * Period to check for mutations (~32 times/sec)
     * @type {number}
     * @expose
     */
    MutationObserver._period = 30 /*ms+runtime*/ ;

    /**
     * Exposed API
     * @expose
     * @final
     */
    MutationObserver.prototype = {
        /**
         * see http://dom.spec.whatwg.org/#dom-mutationobserver-observe
         * not going to throw here but going to follow the current spec config sets
         * @param {Node|null} $target
         * @param {Object|null} config : MutationObserverInit configuration dictionary
         * @expose
         * @return undefined
         */
        observe: function($target, config) {
            /**
             * Using slightly different names so closure can go ham
             * @type {!Object} : A custom mutation config
             */
            var settings = {
                attr: !! (config.attributes || config.attributeFilter || config.attributeOldValue),

                //some browsers are strict in their implementation that config.subtree and childList must be set together. We don't care - spec doesn't specify
                kids: !! config.childList,
                descendents: !! config.subtree,
                charData: !! (config.characterData || config.characterDataOldValue)
            };

            var watched = this._watched;

            //remove already observed target element from pool
            for (var i = 0; i < watched.length; i++) {
                if (watched[i].tar === $target) watched.splice(i, 1);
            }

            if (config.attributeFilter) {
                /**
                 * converts to a {key: true} dict for faster lookup
                 * @type {Object.<String,Boolean>}
                 */
                settings.afilter = reduce(config.attributeFilter, function(a, b) {
                    a[b] = true;
                    return a;
                }, {});
            }

            watched.push({
                tar: $target,
                fn: createMutationSearcher($target, settings)
            });

            //reconnect if not connected
            if (!this._timeout) {
                startMutationChecker(this);
            }
        },

        /**
         * Finds mutations since last check and empties the "record queue" i.e. mutations will only be found once
         * @expose
         * @return {Array.<MutationRecord>}
         */
        takeRecords: function() {
            var mutations = [];
            var watched = this._watched;

            for (var i = 0; i < watched.length; i++) {
                watched[i].fn(mutations);
            }

            return mutations;
        },

        /**
         * @expose
         * @return undefined
         */
        disconnect: function() {
            this._watched = []; //clear the stuff being observed
            clearTimeout(this._timeout); //ready for garbage collection
            /** @private */
            this._timeout = null;
        }
    };

    /**
     * Simple MutationRecord pseudoclass. No longer exposing as its not fully compliant
     * @param {Object} data
     * @return {Object} a MutationRecord
     */
    function MutationRecord(data) {
        var settings = { //technically these should be on proto so hasOwnProperty will return false for non explicitly props
            type: null,
            target: null,
            addedNodes: [],
            removedNodes: [],
            previousSibling: null,
            nextSibling: null,
            attributeName: null,
            attributeNamespace: null,
            oldValue: null
        };
        for (var prop in data) {
            if (has(settings, prop) && data[prop] !== undefined) settings[prop] = data[prop];
        }
        return settings;
    }

    /**
     * Creates a func to find all the mutations
     *
     * @param {Node} $target
     * @param {!Object} config : A custom mutation config
     */
    function createMutationSearcher($target, config) {
        /** type {Elestuct} */
        var $oldstate = clone($target, config); //create the cloned datastructure

        /**
         * consumes array of mutations we can push to
         *
         * @param {Array.<MutationRecord>} mutations
         */
        return function(mutations) {
            var olen = mutations.length;

            //Alright we check base level changes in attributes... easy
            if (config.attr && $oldstate.attr) {
                findAttributeMutations(mutations, $target, $oldstate.attr, config.afilter);
            }

            //check childlist or subtree for mutations
            if (config.kids || config.descendents) {
                searchSubtree(mutations, $target, $oldstate, config);
            }


            //reclone data structure if theres changes
            if (mutations.length !== olen) {
                /** type {Elestuct} */
                $oldstate = clone($target, config);
            }
        };
    }

    /* attributes + attributeFilter helpers */

    /**
     * fast helper to check to see if attributes object of an element has changed
     * doesnt handle the textnode case
     *
     * @param {Array.<MutationRecord>} mutations
     * @param {Node} $target
     * @param {Object.<string, string>} $oldstate : Custom attribute clone data structure from clone
     * @param {Object} filter
     */
    function findAttributeMutations(mutations, $target, $oldstate, filter) {
        var checked = {};
        var attributes = $target.attributes;
        var attr;
        var name;
        var i = attributes.length;
        while (i--) {
            attr = attributes[i];
            name = attr.name;
            if (!filter || has(filter, name)) {
                if (attr.value !== $oldstate[name]) {
                    //The pushing is redundant but gzips very nicely
                    mutations.push(MutationRecord({
                        type: "attributes",
                        target: $target,
                        attributeName: name,
                        oldValue: $oldstate[name],
                        attributeNamespace: attr.namespaceURI //in ie<8 it incorrectly will return undefined
                    }));
                }
                checked[name] = true;
            }
        }
        for (name in $oldstate) {
            if (!(checked[name])) {
                mutations.push(MutationRecord({
                    target: $target,
                    type: "attributes",
                    attributeName: name,
                    oldValue: $oldstate[name]
                }));
            }
        }
    }

    /**
     * searchSubtree: array of mutations so far, element, element clone, bool
     * synchronous dfs comparision of two nodes
     * This function is applied to any observed element with childList or subtree specified
     * Sorry this is kind of confusing as shit, tried to comment it a bit...
     * codereview.stackexchange.com/questions/38351 discussion of an earlier version of this func
     *
     * @param {Array} mutations
     * @param {Node} $target
     * @param {!Object} $oldstate : A custom cloned node from clone()
     * @param {!Object} config : A custom mutation config
     */
    function searchSubtree(mutations, $target, $oldstate, config) {
        /*
         * Helper to identify node rearrangment and stuff...
         * There is no gaurentee that the same node will be identified for both added and removed nodes
         * if the positions have been shuffled.
         * conflicts array will be emptied by end of operation
         */
        function resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes) {
            // the distance between the first conflicting node and the last
            var distance = conflicts.length - 1;
            // prevents same conflict being resolved twice consider when two nodes switch places.
            // only one should be given a mutation event (note -~ is used as a math.ceil shorthand)
            var counter = -~((distance - numAddedNodes) / 2);
            var $cur;
            var oldstruct;
            var conflict;
            while((conflict = conflicts.pop())) {
                $cur = $kids[conflict.i];
                oldstruct = $oldkids[conflict.j];

                //attempt to determine if there was node rearrangement... won't gaurentee all matches
                //also handles case where added/removed nodes cause nodes to be identified as conflicts
                if (config.kids && counter && Math.abs(conflict.i - conflict.j) >= distance) {
                    mutations.push(MutationRecord({
                        type: "childList",
                        target: node,
                        addedNodes: [$cur],
                        removedNodes: [$cur],
                        // haha don't rely on this please
                        nextSibling: $cur.nextSibling,
                        previousSibling: $cur.previousSibling
                    }));
                    counter--; //found conflict
                }

                //Alright we found the resorted nodes now check for other types of mutations
                if (config.attr && oldstruct.attr) findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter);
                if (config.charData && $cur.nodeType === 3 && $cur.nodeValue !== oldstruct.charData) {
                    mutations.push(MutationRecord({
                        type: "characterData",
                        target: $cur,
                        oldValue: oldstruct.charData
                    }));
                }
                //now look @ subtree
                if (config.descendents) findMutations($cur, oldstruct);
            }
        }

        /**
         * Main worker. Finds and adds mutations if there are any
         * @param {Node} node
         * @param {!Object} old : A cloned data structure using internal clone
         */
        function findMutations(node, old) {
            var $kids = node.childNodes;
            var $oldkids = old.kids;
            var klen = $kids.length;
            // $oldkids will be undefined for text and comment nodes
            var olen = $oldkids ? $oldkids.length : 0;
            // if (!olen && !klen) return; //both empty; clearly no changes

            //we delay the intialization of these for marginal performance in the expected case (actually quite signficant on large subtrees when these would be otherwise unused)
            //map of checked element of ids to prevent registering the same conflict twice
            var map;
            //array of potential conflicts (ie nodes that may have been re arranged)
            var conflicts;
            var id; //element id from getElementId helper
            var idx; //index of a moved or inserted element

            var oldstruct;
            //current and old nodes
            var $cur;
            var $old;
            //track the number of added nodes so we can resolve conflicts more accurately
            var numAddedNodes = 0;

            //iterate over both old and current child nodes at the same time
            var i = 0, j = 0;
            //while there is still anything left in $kids or $oldkids (same as i < $kids.length || j < $oldkids.length;)
            while( i < klen || j < olen ) {
                //current and old nodes at the indexs
                $cur = $kids[i];
                oldstruct = $oldkids[j];
                $old = oldstruct && oldstruct.node;

                if ($cur === $old) { //expected case - optimized for this case
                    //check attributes as specified by config
                    if (config.attr && oldstruct.attr) /* oldstruct.attr instead of textnode check */findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter);
                    //check character data if set
                    if (config.charData && $cur.nodeType === 3 && $cur.nodeValue !== oldstruct.charData) {
                        mutations.push(MutationRecord({
                            type: "characterData",
                            target: $cur,
                            oldValue: oldstruct.charData
                        }));
                    }

                    //resolve conflicts; it will be undefined if there are no conflicts - otherwise an array
                    if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes);

                    //recurse on next level of children. Avoids the recursive call when there are no children left to iterate
                    if (config.descendents && ($cur.childNodes.length || oldstruct.kids && oldstruct.kids.length)) findMutations($cur, oldstruct);

                    i++;
                    j++;
                } else { //(uncommon case) lookahead until they are the same again or the end of children
                    if(!map) { //delayed initalization (big perf benefit)
                        map = {};
                        conflicts = [];
                    }
                    if ($cur) {
                        //check id is in the location map otherwise do a indexOf search
                        if (!(map[id = getElementId($cur)])) { //to prevent double checking
                            //mark id as found
                            map[id] = true;
                            //custom indexOf using comparitor checking oldkids[i].node === $cur
                            if ((idx = indexOfCustomNode($oldkids, $cur, j)) === -1) {
                                if (config.kids) {
                                    mutations.push(MutationRecord({
                                        type: "childList",
                                        target: node,
                                        addedNodes: [$cur], //$cur is a new node
                                        nextSibling: $cur.nextSibling,
                                        previousSibling: $cur.previousSibling
                                    }));
                                    numAddedNodes++;
                                }
                            } else {
                                conflicts.push({ //add conflict
                                    i: i,
                                    j: idx
                                });
                            }
                        }
                        i++;
                    }

                    if ($old &&
                       //special case: the changes may have been resolved: i and j appear congurent so we can continue using the expected case
                       $old !== $kids[i]
                    ) {
                        if (!(map[id = getElementId($old)])) {
                            map[id] = true;
                            if ((idx = indexOf($kids, $old, i)) === -1) {
                                if(config.kids) {
                                    mutations.push(MutationRecord({
                                        type: "childList",
                                        target: old.node,
                                        removedNodes: [$old],
                                        nextSibling: $oldkids[j + 1], //praise no indexoutofbounds exception
                                        previousSibling: $oldkids[j - 1]
                                    }));
                                    numAddedNodes--;
                                }
                            } else {
                                conflicts.push({
                                    i: idx,
                                    j: j
                                });
                            }
                        }
                        j++;
                    }
                }//end uncommon case
            }//end loop

            //resolve any remaining conflicts
            if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes);
        }
        findMutations($target, $oldstate);
    }

    /**
     * Utility
     * Cones a element into a custom data structure designed for comparision. https://gist.github.com/megawac/8201012
     *
     * @param {Node} $target
     * @param {!Object} config : A custom mutation config
     * @return {!Object} : Cloned data structure
     */
    function clone($target, config) {
        var recurse = true; // set true so childList we'll always check the first level
        return (function copy($target) {
            var isText = $target.nodeType === 3;
            var elestruct = {
                /** @type {Node} */
                node: $target
            };

            //is text or comemnt node
            if (isText || $target.nodeType === 8) {
                if (isText && config.charData) {
                    elestruct.charData = $target.nodeValue;
                }
            } else { //its either a element or document node (or something stupid)

                if(config.attr && recurse) { // add attr only if subtree is specified or top level
                    /**
                     * clone live attribute list to an object structure {name: val}
                     * @type {Object.<string, string>}
                     */
                    elestruct.attr = reduce($target.attributes, function(memo, attr) {
                        if (!config.afilter || config.afilter[attr.name]) {
                            memo[attr.name] = attr.value;
                        }
                        return memo;
                    }, {});
                }

                // whether we should iterate the children of $target node
                if(recurse && ((config.kids || config.charData) || (config.attr && config.descendents)) ) {
                    /** @type {Array.<!Object>} : Array of custom clone */
                    elestruct.kids = map($target.childNodes, copy);
                }

                recurse = config.descendents;
            }
            return elestruct;
        })($target);
    }

    /**
     * indexOf an element in a collection of custom nodes
     *
     * @param {NodeList} set
     * @param {!Object} $node : A custom cloned node
     * @param {number} idx : index to start the loop
     * @return {number}
     */
    function indexOfCustomNode(set, $node, idx) {
        return indexOf(set, $node, idx, JSCompiler_renameProperty("node"));
    }

    //using a non id (eg outerHTML or nodeValue) is extremely naive and will run into issues with nodes that may appear the same like <li></li>
    var counter = 1; //don't use 0 as id (falsy)
    /** @const */
    var expando = "mo_id";

    /**
     * Attempt to uniquely id an element for hashing. We could optimize this for legacy browsers but it hopefully wont be called enough to be a concern
     *
     * @param {Node} $ele
     * @return {(string|number)}
     */
    function getElementId($ele) {
        try {
            return $ele.id || ($ele[expando] = $ele[expando] || counter++);
        } catch (o_O) { //ie <8 will throw if you set an unknown property on a text node
            try {
                return $ele.nodeValue; //naive
            } catch (shitie) { //when text node is removed: https://gist.github.com/megawac/8355978 :(
                return counter++;
            }
        }
    }

    /**
     * **map** Apply a mapping function to each item of a set
     * @param {Array|NodeList} set
     * @param {Function} iterator
     */
    function map(set, iterator) {
        var results = [];
        for (var index = 0; index < set.length; index++) {
            results[index] = iterator(set[index], index, set);
        }
        return results;
    }

    /**
     * **Reduce** builds up a single result from a list of values
     * @param {Array|NodeList|NamedNodeMap} set
     * @param {Function} iterator
     * @param {*} [memo] Initial value of the memo.
     */
    function reduce(set, iterator, memo) {
        for (var index = 0; index < set.length; index++) {
            memo = iterator(memo, set[index], index, set);
        }
        return memo;
    }

    /**
     * **indexOf** find index of item in collection.
     * @param {Array|NodeList} set
     * @param {Object} item
     * @param {number} idx
     * @param {string} [prop] Property on set item to compare to item
     */
    function indexOf(set, item, idx, prop) {
        for (/*idx = ~~idx*/; idx < set.length; idx++) {//start idx is always given as this is internal
            if ((prop ? set[idx][prop] : set[idx]) === item) return idx;
        }
        return -1;
    }

    /**
     * @param {Object} obj
     * @param {(string|number)} prop
     * @return {boolean}
     */
    function has(obj, prop) {
        return obj[prop] !== undefined; //will be nicely inlined by gcc
    }

    // GCC hack see http://stackoverflow.com/a/23202438/1517919
    function JSCompiler_renameProperty(a) {
        return a;
    }

    return MutationObserver;
})(void 0);

/*!
 * @overview es6-promise - a tiny implementation of Promises/A+.
 * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
 * @license   Licensed under MIT license
 *            See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
 * @version   2.0.1
 */

(function() {
    "use strict";
    function lib$es6$promise$utils$$objectOrFunction(x) {
      return typeof x === 'function' || (typeof x === 'object' && x !== null);
    }

    function lib$es6$promise$utils$$isFunction(x) {
      return typeof x === 'function';
    }

    function lib$es6$promise$utils$$isMaybeThenable(x) {
      return typeof x === 'object' && x !== null;
    }

    var lib$es6$promise$utils$$_isArray;
    if (!Array.isArray) {
      lib$es6$promise$utils$$_isArray = function (x) {
        return Object.prototype.toString.call(x) === '[object Array]';
      };
    } else {
      lib$es6$promise$utils$$_isArray = Array.isArray;
    }

    var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray;

    var lib$es6$promise$utils$$now = Date.now || function() { return new Date().getTime(); };

    function lib$es6$promise$utils$$F() { }

    var lib$es6$promise$utils$$o_create = (Object.create || function (o) {
      if (arguments.length > 1) {
        throw new Error('Second argument not supported');
      }
      if (typeof o !== 'object') {
        throw new TypeError('Argument must be an object');
      }
      lib$es6$promise$utils$$F.prototype = o;
      return new lib$es6$promise$utils$$F();
    });
    var lib$es6$promise$asap$$len = 0;
    var lib$es6$promise$asap$$toString = {}.toString;
    var lib$es6$promise$asap$$vertxNext;
    function lib$es6$promise$asap$$asap(callback, arg) {
      lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback;
      lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg;
      lib$es6$promise$asap$$len += 2;
      if (lib$es6$promise$asap$$len === 2) {
        // If len is 1, that means that we need to schedule an async flush.
        // If additional callbacks are queued before the queue is flushed, they
        // will be processed by this flush that we are scheduling.
        lib$es6$promise$asap$$scheduleFlush();
      }
    }

    var lib$es6$promise$asap$$default = lib$es6$promise$asap$$asap;

    var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined;
    var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {};
    var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver;
    var lib$es6$promise$asap$$isNode = typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';

    // test for web worker but not in IE10
    var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
      typeof importScripts !== 'undefined' &&
      typeof MessageChannel !== 'undefined';

    // node
    function lib$es6$promise$asap$$useNextTick() {
      var nextTick = process.nextTick;
      // node version 0.10.x displays a deprecation warning when nextTick is used recursively
      // setImmediate should be used instead instead
      var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/);
      if (Array.isArray(version) && version[1] === '0' && version[2] === '10') {
        nextTick = setImmediate;
      }
      return function() {
        nextTick(lib$es6$promise$asap$$flush);
      };
    }

    // vertx
    function lib$es6$promise$asap$$useVertxTimer() {
      return function() {
        lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush);
      };
    }

    function lib$es6$promise$asap$$useMutationObserver() {
      var iterations = 0;
      var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush);
      var node = document.createTextNode('');
      observer.observe(node, { characterData: true });
    
      return function() {
        node.data = (iterations = ++iterations % 2);
      };
    }

    // web worker
    function lib$es6$promise$asap$$useMessageChannel() {
      var channel = new MessageChannel();
      channel.port1.onmessage = lib$es6$promise$asap$$flush;
      return function () {
        channel.port2.postMessage(0);
      };
    }

    function lib$es6$promise$asap$$useSetTimeout() {
      return function() {
        setTimeout(lib$es6$promise$asap$$flush, 1);
      };
    }

    var lib$es6$promise$asap$$queue = new Array(1000);
    function lib$es6$promise$asap$$flush() {
      for (var i = 0; i < lib$es6$promise$asap$$len; i+=2) {
        var callback = lib$es6$promise$asap$$queue[i];
        var arg = lib$es6$promise$asap$$queue[i+1];
    
        callback(arg);
    
        lib$es6$promise$asap$$queue[i] = undefined;
        lib$es6$promise$asap$$queue[i+1] = undefined;
      }
    
      lib$es6$promise$asap$$len = 0;
    }

    function lib$es6$promise$asap$$attemptVertex() {
      try {
        var r = require;
        var vertx = r('vertx');
        lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext;
        return lib$es6$promise$asap$$useVertxTimer();
      } catch(e) {
        return lib$es6$promise$asap$$useSetTimeout();
      }
    }

    var lib$es6$promise$asap$$scheduleFlush;
    // Decide what async method to use to triggering processing of queued callbacks:
    if (lib$es6$promise$asap$$isNode) {
      lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick();
    } else if (lib$es6$promise$asap$$BrowserMutationObserver &&
               typeof MutationRecord !== "undefined") {
      lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver();
    } else if (lib$es6$promise$asap$$isWorker) {
      lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel();
    } else if (lib$es6$promise$asap$$browserWindow === undefined && typeof require === 'function') {
      lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertex();
    } else {
      lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout();
    }

    function lib$es6$promise$$internal$$noop() {}

    var lib$es6$promise$$internal$$PENDING   = void 0;
    var lib$es6$promise$$internal$$FULFILLED = 1;
    var lib$es6$promise$$internal$$REJECTED  = 2;

    var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject();

    function lib$es6$promise$$internal$$selfFullfillment() {
      return new TypeError("You cannot resolve a promise with itself");
    }

    function lib$es6$promise$$internal$$cannotReturnOwn() {
      return new TypeError('A promises callback cannot return that same promise.')
    }

    function lib$es6$promise$$internal$$getThen(promise) {
      try {
        return promise.then;
      } catch(error) {
        lib$es6$promise$$internal$$GET_THEN_ERROR.error = error;
        return lib$es6$promise$$internal$$GET_THEN_ERROR;
      }
    }

    function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
      try {
        then.call(value, fulfillmentHandler, rejectionHandler);
      } catch(e) {
        return e;
      }
    }

    function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) {
       lib$es6$promise$asap$$default(function(promise) {
        var sealed = false;
        var error = lib$es6$promise$$internal$$tryThen(then, thenable, function(value) {
          if (sealed) { return; }
          sealed = true;
          if (thenable !== value) {
            lib$es6$promise$$internal$$resolve(promise, value);
          } else {
            lib$es6$promise$$internal$$fulfill(promise, value);
          }
        }, function(reason) {
          if (sealed) { return; }
          sealed = true;
    
          lib$es6$promise$$internal$$reject(promise, reason);
        }, 'Settle: ' + (promise._label || ' unknown promise'));
    
        if (!sealed && error) {
          sealed = true;
          lib$es6$promise$$internal$$reject(promise, error);
        }
      }, promise);
    }

    function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) {
      if (thenable._state === lib$es6$promise$$internal$$FULFILLED) {
        lib$es6$promise$$internal$$fulfill(promise, thenable._result);
      } else if (promise._state === lib$es6$promise$$internal$$REJECTED) {
        lib$es6$promise$$internal$$reject(promise, thenable._result);
      } else {
        lib$es6$promise$$internal$$subscribe(thenable, undefined, function(value) {
          lib$es6$promise$$internal$$resolve(promise, value);
        }, function(reason) {
          lib$es6$promise$$internal$$reject(promise, reason);
        });
      }
    }

    function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable) {
      if (maybeThenable.constructor === promise.constructor) {
        lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable);
      } else {
        var then = lib$es6$promise$$internal$$getThen(maybeThenable);
    
        if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) {
          lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error);
        } else if (then === undefined) {
          lib$es6$promise$$internal$$fulfill(promise, maybeThenable);
        } else if (lib$es6$promise$utils$$isFunction(then)) {
          lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then);
        } else {
          lib$es6$promise$$internal$$fulfill(promise, maybeThenable);
        }
      }
    }

    function lib$es6$promise$$internal$$resolve(promise, value) {
      if (promise === value) {
        lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFullfillment());
      } else if (lib$es6$promise$utils$$objectOrFunction(value)) {
        lib$es6$promise$$internal$$handleMaybeThenable(promise, value);
      } else {
        lib$es6$promise$$internal$$fulfill(promise, value);
      }
    }

    function lib$es6$promise$$internal$$publishRejection(promise) {
      if (promise._onerror) {
        promise._onerror(promise._result);
      }
    
      lib$es6$promise$$internal$$publish(promise);
    }

    function lib$es6$promise$$internal$$fulfill(promise, value) {
      if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; }
    
      promise._result = value;
      promise._state = lib$es6$promise$$internal$$FULFILLED;
    
      if (promise._subscribers.length === 0) {
      } else {
        lib$es6$promise$asap$$default(lib$es6$promise$$internal$$publish, promise);
      }
    }

    function lib$es6$promise$$internal$$reject(promise, reason) {
      if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; }
      promise._state = lib$es6$promise$$internal$$REJECTED;
      promise._result = reason;
    
      lib$es6$promise$asap$$default(lib$es6$promise$$internal$$publishRejection, promise);
    }

    function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
      var subscribers = parent._subscribers;
      var length = subscribers.length;
    
      parent._onerror = null;
    
      subscribers[length] = child;
      subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment;
      subscribers[length + lib$es6$promise$$internal$$REJECTED]  = onRejection;
    
      if (length === 0 && parent._state) {
        lib$es6$promise$asap$$default(lib$es6$promise$$internal$$publish, parent);
      }
    }

    function lib$es6$promise$$internal$$publish(promise) {
      var subscribers = promise._subscribers;
      var settled = promise._state;
    
      if (subscribers.length === 0) { return; }
    
      var child, callback, detail = promise._result;
    
      for (var i = 0; i < subscribers.length; i += 3) {
        child = subscribers[i];
        callback = subscribers[i + settled];
    
        if (child) {
          lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail);
        } else {
          callback(detail);
        }
      }
    
      promise._subscribers.length = 0;
    }

    function lib$es6$promise$$internal$$ErrorObject() {
      this.error = null;
    }

    var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject();

    function lib$es6$promise$$internal$$tryCatch(callback, detail) {
      try {
        return callback(detail);
      } catch(e) {
        lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e;
        return lib$es6$promise$$internal$$TRY_CATCH_ERROR;
      }
    }

    function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) {
      var hasCallback = lib$es6$promise$utils$$isFunction(callback),
          value, error, succeeded, failed;
    
      if (hasCallback) {
        value = lib$es6$promise$$internal$$tryCatch(callback, detail);
    
        if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) {
          failed = true;
          error = value.error;
          value = null;
        } else {
          succeeded = true;
        }
    
        if (promise === value) {
          lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn());
          return;
        }
    
      } else {
        value = detail;
        succeeded = true;
      }
    
      if (promise._state !== lib$es6$promise$$internal$$PENDING) {
        // noop
      } else if (hasCallback && succeeded) {
        lib$es6$promise$$internal$$resolve(promise, value);
      } else if (failed) {
        lib$es6$promise$$internal$$reject(promise, error);
      } else if (settled === lib$es6$promise$$internal$$FULFILLED) {
        lib$es6$promise$$internal$$fulfill(promise, value);
      } else if (settled === lib$es6$promise$$internal$$REJECTED) {
        lib$es6$promise$$internal$$reject(promise, value);
      }
    }

    function lib$es6$promise$$internal$$initializePromise(promise, resolver) {
      try {
        resolver(function resolvePromise(value){
          lib$es6$promise$$internal$$resolve(promise, value);
        }, function rejectPromise(reason) {
          lib$es6$promise$$internal$$reject(promise, reason);
        });
      } catch(e) {
        lib$es6$promise$$internal$$reject(promise, e);
      }
    }

    function lib$es6$promise$enumerator$$makeSettledResult(state, position, value) {
      if (state === lib$es6$promise$$internal$$FULFILLED) {
        return {
          state: 'fulfilled',
          value: value
        };
      } else {
        return {
          state: 'rejected',
          reason: value
        };
      }
    }

    function lib$es6$promise$enumerator$$Enumerator(Constructor, input, abortOnReject, label) {
      this._instanceConstructor = Constructor;
      this.promise = new Constructor(lib$es6$promise$$internal$$noop, label);
      this._abortOnReject = abortOnReject;
    
      if (this._validateInput(input)) {
        this._input     = input;
        this.length     = input.length;
        this._remaining = input.length;
    
        this._init();
    
        if (this.length === 0) {
          lib$es6$promise$$internal$$fulfill(this.promise, this._result);
        } else {
          this.length = this.length || 0;
          this._enumerate();
          if (this._remaining === 0) {
            lib$es6$promise$$internal$$fulfill(this.promise, this._result);
          }
        }
      } else {
        lib$es6$promise$$internal$$reject(this.promise, this._validationError());
      }
    }

    lib$es6$promise$enumerator$$Enumerator.prototype._validateInput = function(input) {
      return lib$es6$promise$utils$$isArray(input);
    };

    lib$es6$promise$enumerator$$Enumerator.prototype._validationError = function() {
      return new Error('Array Methods must be provided an Array');
    };

    lib$es6$promise$enumerator$$Enumerator.prototype._init = function() {
      this._result = new Array(this.length);
    };

    var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator;

    lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function() {
      var length  = this.length;
      var promise = this.promise;
      var input   = this._input;
    
      for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) {
        this._eachEntry(input[i], i);
      }
    };

    lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) {
      var c = this._instanceConstructor;
      if (lib$es6$promise$utils$$isMaybeThenable(entry)) {
        if (entry.constructor === c && entry._state !== lib$es6$promise$$internal$$PENDING) {
          entry._onerror = null;
          this._settledAt(entry._state, i, entry._result);
        } else {
          this._willSettleAt(c.resolve(entry), i);
        }
      } else {
        this._remaining--;
        this._result[i] = this._makeResult(lib$es6$promise$$internal$$FULFILLED, i, entry);
      }
    };

    lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) {
      var promise = this.promise;
    
      if (promise._state === lib$es6$promise$$internal$$PENDING) {
        this._remaining--;
    
        if (this._abortOnReject && state === lib$es6$promise$$internal$$REJECTED) {
          lib$es6$promise$$internal$$reject(promise, value);
        } else {
          this._result[i] = this._makeResult(state, i, value);
        }
      }
    
      if (this._remaining === 0) {
        lib$es6$promise$$internal$$fulfill(promise, this._result);
      }
    };

    lib$es6$promise$enumerator$$Enumerator.prototype._makeResult = function(state, i, value) {
      return value;
    };

    lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) {
      var enumerator = this;
    
      lib$es6$promise$$internal$$subscribe(promise, undefined, function(value) {
        enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value);
      }, function(reason) {
        enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason);
      });
    };
    function lib$es6$promise$promise$all$$all(entries, label) {
      return new lib$es6$promise$enumerator$$default(this, entries, true /* abort on reject */, label).promise;
    }
    var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all;
    function lib$es6$promise$promise$race$$race(entries, label) {
      /*jshint validthis:true */
      var Constructor = this;
    
      var promise = new Constructor(lib$es6$promise$$internal$$noop, label);
    
      if (!lib$es6$promise$utils$$isArray(entries)) {
        lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.'));
        return promise;
      }
    
      var length = entries.length;
    
      function onFulfillment(value) {
        lib$es6$promise$$internal$$resolve(promise, value);
      }
    
      function onRejection(reason) {
        lib$es6$promise$$internal$$reject(promise, reason);
      }
    
      for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) {
        lib$es6$promise$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection);
      }
    
      return promise;
    }
    var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race;
    function lib$es6$promise$promise$resolve$$resolve(object, label) {
      /*jshint validthis:true */
      var Constructor = this;
    
      if (object && typeof object === 'object' && object.constructor === Constructor) {
        return object;
      }
    
      var promise = new Constructor(lib$es6$promise$$internal$$noop, label);
      lib$es6$promise$$internal$$resolve(promise, object);
      return promise;
    }
    var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve;
    function lib$es6$promise$promise$reject$$reject(reason, label) {
      /*jshint validthis:true */
      var Constructor = this;
      var promise = new Constructor(lib$es6$promise$$internal$$noop, label);
      lib$es6$promise$$internal$$reject(promise, reason);
      return promise;
    }
    var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject;

    var lib$es6$promise$promise$$counter = 0;

    function lib$es6$promise$promise$$needsResolver() {
      throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
    }

    function lib$es6$promise$promise$$needsNew() {
      throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
    }

    var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise;
    /**
      Promise objects represent the eventual result of an asynchronous operation. The
      primary way of interacting with a promise is through its `then` method, which
      registers callbacks to receive either a promise’s eventual value or the reason
      why the promise cannot be fulfilled.

      Terminology
      -----------

      - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
      - `thenable` is an object or function that defines a `then` method.
      - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
      - `exception` is a value that is thrown using the throw statement.
      - `reason` is a value that indicates why a promise was rejected.
      - `settled` the final resting state of a promise, fulfilled or rejected.

      A promise can be in one of three states: pending, fulfilled, or rejected.

      Promises that are fulfilled have a fulfillment value and are in the fulfilled
      state.  Promises that are rejected have a rejection reason and are in the
      rejected state.  A fulfillment value is never a thenable.

      Promises can also be said to *resolve* a value.  If this value is also a
      promise, then the original promise's settled state will match the value's
      settled state.  So a promise that *resolves* a promise that rejects will
      itself reject, and a promise that *resolves* a promise that fulfills will
      itself fulfill.


      Basic Usage:
      ------------

      ```js
      var promise = new Promise(function(resolve, reject) {
        // on success
        resolve(value);

        // on failure
        reject(reason);
      });

      promise.then(function(value) {
        // on fulfillment
      }, function(reason) {
        // on rejection
      });
      ```

      Advanced Usage:
      ---------------

      Promises shine when abstracting away asynchronous interactions such as
      `XMLHttpRequest`s.

      ```js
      function getJSON(url) {
        return new Promise(function(resolve, reject){
          var xhr = new XMLHttpRequest();

          xhr.open('GET', url);
          xhr.onreadystatechange = handler;
          xhr.responseType = 'json';
          xhr.setRequestHeader('Accept', 'application/json');
          xhr.send();

          function handler() {
            if (this.readyState === this.DONE) {
              if (this.status === 200) {
                resolve(this.response);
              } else {
                reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
              }
            }
          };
        });
      }

      getJSON('/posts.json').then(function(json) {
        // on fulfillment
      }, function(reason) {
        // on rejection
      });
      ```

      Unlike callbacks, promises are great composable primitives.

      ```js
      Promise.all([
        getJSON('/posts'),
        getJSON('/comments')
      ]).then(function(values){
        values[0] // => postsJSON
        values[1] // => commentsJSON

        return values;
      });
      ```

      @class Promise
      @param {function} resolver
      Useful for tooling.
      @constructor
    */
    function lib$es6$promise$promise$$Promise(resolver) {
      this._id = lib$es6$promise$promise$$counter++;
      this._state = undefined;
      this._result = undefined;
      this._subscribers = [];
    
      if (lib$es6$promise$$internal$$noop !== resolver) {
        if (!lib$es6$promise$utils$$isFunction(resolver)) {
          lib$es6$promise$promise$$needsResolver();
        }
    
        if (!(this instanceof lib$es6$promise$promise$$Promise)) {
          lib$es6$promise$promise$$needsNew();
        }
    
        lib$es6$promise$$internal$$initializePromise(this, resolver);
      }
    }

    lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default;
    lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default;
    lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default;
    lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default;

    lib$es6$promise$promise$$Promise.prototype = {
      constructor: lib$es6$promise$promise$$Promise,
    
    /**
      The primary way of interacting with a promise is through its `then` method,
      which registers callbacks to receive either a promise's eventual value or the
      reason why the promise cannot be fulfilled.
    
      ```js
      findUser().then(function(user){
        // user is available
      }, function(reason){
        // user is unavailable, and you are given the reason why
      });
      ```
    
      Chaining
      --------
    
      The return value of `then` is itself a promise.  This second, 'downstream'
      promise is resolved with the return value of the first promise's fulfillment
      or rejection handler, or rejected if the handler throws an exception.
    
      ```js
      findUser().then(function (user) {
        return user.name;
      }, function (reason) {
        return 'default name';
      }).then(function (userName) {
        // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
        // will be `'default name'`
      });
    
      findUser().then(function (user) {
        throw new Error('Found user, but still unhappy');
      }, function (reason) {
        throw new Error('`findUser` rejected and we're unhappy');
      }).then(function (value) {
        // never reached
      }, function (reason) {
        // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
        // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
      });
      ```
      If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
    
      ```js
      findUser().then(function (user) {
        throw new PedagogicalException('Upstream error');
      }).then(function (value) {
        // never reached
      }).then(function (value) {
        // never reached
      }, function (reason) {
        // The `PedgagocialException` is propagated all the way down to here
      });
      ```
    
      Assimilation
      ------------
    
      Sometimes the value you want to propagate to a downstream promise can only be
      retrieved asynchronously. This can be achieved by returning a promise in the
      fulfillment or rejection handler. The downstream promise will then be pending
      until the returned promise is settled. This is called *assimilation*.
    
      ```js
      findUser().then(function (user) {
        return findCommentsByAuthor(user);
      }).then(function (comments) {
        // The user's comments are now available
      });
      ```
    
      If the assimliated promise rejects, then the downstream promise will also reject.
    
      ```js
      findUser().then(function (user) {
        return findCommentsByAuthor(user);
      }).then(function (comments) {
        // If `findCommentsByAuthor` fulfills, we'll have the value here
      }, function (reason) {
        // If `findCommentsByAuthor` rejects, we'll have the reason here
      });
      ```
    
      Simple Example
      --------------
    
      Synchronous Example
    
      ```javascript
      var result;
    
      try {
        result = findResult();
        // success
      } catch(reason) {
        // failure
      }
      ```
    
      Errback Example
    
      ```js
      findResult(function(result, err){
        if (err) {
          // failure
        } else {
          // success
        }
      });
      ```
    
      Promise Example;
    
      ```javascript
      findResult().then(function(result){
        // success
      }, function(reason){
        // failure
      });
      ```
    
      Advanced Example
      --------------
    
      Synchronous Example
    
      ```javascript
      var author, books;
    
      try {
        author = findAuthor();
        books  = findBooksByAuthor(author);
        // success
      } catch(reason) {
        // failure
      }
      ```
    
      Errback Example
    
      ```js
    
      function foundBooks(books) {
    
      }
    
      function failure(reason) {
    
      }
    
      findAuthor(function(author, err){
        if (err) {
          failure(err);
          // failure
        } else {
          try {
            findBoooksByAuthor(author, function(books, err) {
              if (err) {
                failure(err);
              } else {
                try {
                  foundBooks(books);
                } catch(reason) {
                  failure(reason);
                }
              }
            });
          } catch(error) {
            failure(err);
          }
          // success
        }
      });
      ```
    
      Promise Example;
    
      ```javascript
      findAuthor().
        then(findBooksByAuthor).
        then(function(books){
          // found books
      }).catch(function(reason){
        // something went wrong
      });
      ```
    
      @method then
      @param {Function} onFulfilled
      @param {Function} onRejected
      Useful for tooling.
      @return {Promise}
    */
      then: function(onFulfillment, onRejection) {
        var parent = this;
        var state = parent._state;
    
        if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) {
          return this;
        }
    
        var child = new this.constructor(lib$es6$promise$$internal$$noop);
        var result = parent._result;
    
        if (state) {
          var callback = arguments[state - 1];
          lib$es6$promise$asap$$default(function(){
            lib$es6$promise$$internal$$invokeCallback(state, child, callback, result);
          });
        } else {
          lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection);
        }
    
        return child;
      },
    
    /**
      `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
      as the catch block of a try/catch statement.
    
      ```js
      function findAuthor(){
        throw new Error('couldn't find that author');
      }
    
      // synchronous
      try {
        findAuthor();
      } catch(reason) {
        // something went wrong
      }
    
      // async with promises
      findAuthor().catch(function(reason){
        // something went wrong
      });
      ```
    
      @method catch
      @param {Function} onRejection
      Useful for tooling.
      @return {Promise}
    */
      'catch': function(onRejection) {
        return this.then(null, onRejection);
      }
    };
    function lib$es6$promise$polyfill$$polyfill() {
      var local = (typeof global !== 'undefined') ? global : self;
      var P = local.Promise;
    
      if (P && Object.prototype.toString.call(lib$es6$promise$promise$$default.resolve()) === '[object Promise]' && !lib$es6$promise$promise$$default.cast) {
        try {
          var K = function (r) { P.call(this, r); }
          K.prototype = Object.create(P.prototype);
          new K(function() { })
          return;
        } catch(e) {
          // Promise is not subclassable
        }
      }
    
      local.Promise = lib$es6$promise$promise$$default;
    }
    var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill;

    var lib$es6$promise$umd$$ES6Promise = {
      'Promise': lib$es6$promise$promise$$default,
      'polyfill': lib$es6$promise$polyfill$$default
    };

    /* global define:true module:true window: true */
    if (typeof define === 'function' && define['amd']) {
      define(function() { return lib$es6$promise$umd$$ES6Promise; });
    } else if (typeof module !== 'undefined' && module['exports']) {
      module['exports'] = lib$es6$promise$umd$$ES6Promise;
    } else if (typeof this !== 'undefined') {
      this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise;
    }

    lib$es6$promise$polyfill$$default();
}).call(this);


// Copyright 2006 Google Inc.
//
// 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.


// Known Issues:
//
// * Patterns are not implemented.
// * Radial gradient are not implemented. The VML version of these look very
//   different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
//   width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
//   Quirks mode will draw the canvas using border-box. Either change your
//   doctype to HTML5
//   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
//   or use Box Sizing Behavior from WebFX
//   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Non uniform scaling does not correctly scale strokes.
// * Optimize. There is always room for speed improvements.

// Only add this code if we do not already have a canvas implementation
if (!document.createElement('canvas').getContext) {

(function() {

  // alias some functions to make (compiled) code shorter
  var m = Math;
  var mr = m.round;
  var ms = m.sin;
  var mc = m.cos;
  var abs = m.abs;
  var sqrt = m.sqrt;

  // this is used for sub pixel precision
  var Z = 10;
  var Z2 = Z / 2;

  /**
   * This funtion is assigned to the <canvas> elements as element.getContext().
   * @this {HTMLElement}
   * @return {CanvasRenderingContext2D_}
   */
  function getContext() {
    return this.context_ ||
        (this.context_ = new CanvasRenderingContext2D_(this));
  }

  var slice = Array.prototype.slice;

  /**
   * Binds a function to an object. The returned function will always use the
   * passed in {@code obj} as {@code this}.
   *
   * Example:
   *
   *   g = bind(f, obj, a, b)
   *   g(c, d) // will do f.call(obj, a, b, c, d)
   *
   * @param {Function} f The function to bind the object to
   * @param {Object} obj The object that should act as this when the function
   *     is called
   * @param {*} var_args Rest arguments that will be used as the initial
   *     arguments when the function is called
   * @return {Function} A new function that has bound this
   */
  function bind(f, obj, var_args) {
    var a = slice.call(arguments, 2);
    return function() {
      return f.apply(obj, a.concat(slice.call(arguments)));
    };
  }

  var G_vmlCanvasManager_ = {
    init: function(opt_doc) {
      if (/MSIE/.test(navigator.userAgent) && !window.opera) {
        var doc = opt_doc || document;
        // Create a dummy element so that IE will allow canvas elements to be
        // recognized.
        doc.createElement('canvas');
        doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
      }
    },

    init_: function(doc) {
      // create xmlns
      if (!doc.namespaces['g_vml_']) {
        doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
                           '#default#VML');

      }
      if (!doc.namespaces['g_o_']) {
        doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
                           '#default#VML');
      }

      // Setup default CSS.  Only add one style sheet per document
      if (!doc.styleSheets['ex_canvas_']) {
        var ss = doc.createStyleSheet();
        ss.owningElement.id = 'ex_canvas_';
        ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
            // default size is 300x150 in Gecko and Opera
            'text-align:left;width:300px;height:150px}' +
            'g_vml_\\:*{behavior:url(#default#VML)}' +
            'g_o_\\:*{behavior:url(#default#VML)}';

      }

      // find all canvas elements
      var els = doc.getElementsByTagName('canvas');
      for (var i = 0; i < els.length; i++) {
        this.initElement(els[i]);
      }
    },

    /**
     * Public initializes a canvas element so that it can be used as canvas
     * element from now on. This is called automatically before the page is
     * loaded but if you are creating elements using createElement you need to
     * make sure this is called on the element.
     * @param {HTMLElement} el The canvas element to initialize.
     * @return {HTMLElement} the element that was created.
     */
    initElement: function(el) {
      if (!el.getContext) {

        el.getContext = getContext;

        // Remove fallback content. There is no way to hide text nodes so we
        // just remove all childNodes. We could hide all elements and remove
        // text nodes but who really cares about the fallback content.
        el.innerHTML = '';

        // do not use inline function because that will leak memory
        el.attachEvent('onpropertychange', onPropertyChange);
        el.attachEvent('onresize', onResize);

        var attrs = el.attributes;
        if (attrs.width && attrs.width.specified) {
          // TODO: use runtimeStyle and coordsize
          // el.getContext().setWidth_(attrs.width.nodeValue);
          el.style.width = attrs.width.nodeValue + 'px';
        } else {
          el.width = el.clientWidth;
        }
        if (attrs.height && attrs.height.specified) {
          // TODO: use runtimeStyle and coordsize
          // el.getContext().setHeight_(attrs.height.nodeValue);
          el.style.height = attrs.height.nodeValue + 'px';
        } else {
          el.height = el.clientHeight;
        }
        //el.getContext().setCoordsize_()
      }
      return el;
    }
  };

  function onPropertyChange(e) {
    var el = e.srcElement;

    switch (e.propertyName) {
      case 'width':
        el.style.width = el.attributes.width.nodeValue + 'px';
        el.getContext().clearRect();
        break;
      case 'height':
        el.style.height = el.attributes.height.nodeValue + 'px';
        el.getContext().clearRect();
        break;
    }
  }

  function onResize(e) {
    var el = e.srcElement;
    if (el.firstChild) {
      el.firstChild.style.width =  el.clientWidth + 'px';
      el.firstChild.style.height = el.clientHeight + 'px';
    }
  }

  G_vmlCanvasManager_.init();

  // precompute "00" to "FF"
  var dec2hex = [];
  for (var i = 0; i < 16; i++) {
    for (var j = 0; j < 16; j++) {
      dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
    }
  }

  function createMatrixIdentity() {
    return [
      [1, 0, 0],
      [0, 1, 0],
      [0, 0, 1]
    ];
  }

  function matrixMultiply(m1, m2) {
    var result = createMatrixIdentity();

    for (var x = 0; x < 3; x++) {
      for (var y = 0; y < 3; y++) {
        var sum = 0;

        for (var z = 0; z < 3; z++) {
          sum += m1[x][z] * m2[z][y];
        }

        result[x][y] = sum;
      }
    }
    return result;
  }

  function copyState(o1, o2) {
    o2.fillStyle     = o1.fillStyle;
    o2.lineCap       = o1.lineCap;
    o2.lineJoin      = o1.lineJoin;
    o2.lineWidth     = o1.lineWidth;
    o2.miterLimit    = o1.miterLimit;
    o2.shadowBlur    = o1.shadowBlur;
    o2.shadowColor   = o1.shadowColor;
    o2.shadowOffsetX = o1.shadowOffsetX;
    o2.shadowOffsetY = o1.shadowOffsetY;
    o2.strokeStyle   = o1.strokeStyle;
    o2.globalAlpha   = o1.globalAlpha;
    o2.arcScaleX_    = o1.arcScaleX_;
    o2.arcScaleY_    = o1.arcScaleY_;
    o2.lineScale_    = o1.lineScale_;
  }

  function processStyle(styleString) {
    var str, alpha = 1;

    styleString = String(styleString);
    if (styleString.substring(0, 3) == 'rgb') {
      var start = styleString.indexOf('(', 3);
      var end = styleString.indexOf(')', start + 1);
      var guts = styleString.substring(start + 1, end).split(',');

      str = '#';
      for (var i = 0; i < 3; i++) {
        str += dec2hex[Number(guts[i])];
      }

      if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
        alpha = guts[3];
      }
    } else {
      str = styleString;
    }

    return {color: str, alpha: alpha};
  }

  function processLineCap(lineCap) {
    switch (lineCap) {
      case 'butt':
        return 'flat';
      case 'round':
        return 'round';
      case 'square':
      default:
        return 'square';
    }
  }

  /**
   * This class implements CanvasRenderingContext2D interface as described by
   * the WHATWG.
   * @param {HTMLElement} surfaceElement The element that the 2D context should
   * be associated with
   */
  function CanvasRenderingContext2D_(surfaceElement) {
    this.m_ = createMatrixIdentity();

    this.mStack_ = [];
    this.aStack_ = [];
    this.currentPath_ = [];

    // Canvas context properties
    this.strokeStyle = '#000';
    this.fillStyle = '#000';

    this.lineWidth = 1;
    this.lineJoin = 'miter';
    this.lineCap = 'butt';
    this.miterLimit = Z * 1;
    this.globalAlpha = 1;
    this.canvas = surfaceElement;

    var el = surfaceElement.ownerDocument.createElement('div');
    el.style.width =  surfaceElement.clientWidth + 'px';
    el.style.height = surfaceElement.clientHeight + 'px';
    el.style.overflow = 'hidden';
    el.style.position = 'absolute';
    surfaceElement.appendChild(el);

    this.element_ = el;
    this.arcScaleX_ = 1;
    this.arcScaleY_ = 1;
    this.lineScale_ = 1;
  }

  var contextPrototype = CanvasRenderingContext2D_.prototype;
  contextPrototype.clearRect = function() {
    this.element_.innerHTML = '';
  };

  contextPrototype.beginPath = function() {
    // TODO: Branch current matrix so that save/restore has no effect
    //       as per safari docs.
    this.currentPath_ = [];
  };

  contextPrototype.moveTo = function(aX, aY) {
    var p = this.getCoords_(aX, aY);
    this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
    this.currentX_ = p.x;
    this.currentY_ = p.y;
  };

  contextPrototype.lineTo = function(aX, aY) {
    var p = this.getCoords_(aX, aY);
    this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});

    this.currentX_ = p.x;
    this.currentY_ = p.y;
  };

  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
                                            aCP2x, aCP2y,
                                            aX, aY) {
    var p = this.getCoords_(aX, aY);
    var cp1 = this.getCoords_(aCP1x, aCP1y);
    var cp2 = this.getCoords_(aCP2x, aCP2y);
    bezierCurveTo(this, cp1, cp2, p);
  };

  // Helper function that takes the already fixed cordinates.
  function bezierCurveTo(self, cp1, cp2, p) {
    self.currentPath_.push({
      type: 'bezierCurveTo',
      cp1x: cp1.x,
      cp1y: cp1.y,
      cp2x: cp2.x,
      cp2y: cp2.y,
      x: p.x,
      y: p.y
    });
    self.currentX_ = p.x;
    self.currentY_ = p.y;
  }

  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
    // the following is lifted almost directly from
    // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes

    var cp = this.getCoords_(aCPx, aCPy);
    var p = this.getCoords_(aX, aY);

    var cp1 = {
      x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
      y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
    };
    var cp2 = {
      x: cp1.x + (p.x - this.currentX_) / 3.0,
      y: cp1.y + (p.y - this.currentY_) / 3.0
    };

    bezierCurveTo(this, cp1, cp2, p);
  };

  contextPrototype.arc = function(aX, aY, aRadius,
                                  aStartAngle, aEndAngle, aClockwise) {
    aRadius *= Z;
    var arcType = aClockwise ? 'at' : 'wa';

    var xStart = aX + mc(aStartAngle) * aRadius - Z2;
    var yStart = aY + ms(aStartAngle) * aRadius - Z2;

    var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
    var yEnd = aY + ms(aEndAngle) * aRadius - Z2;

    // IE won't render arches drawn counter clockwise if xStart == xEnd.
    if (xStart == xEnd && !aClockwise) {
      xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
                       // that can be represented in binary
    }

    var p = this.getCoords_(aX, aY);
    var pStart = this.getCoords_(xStart, yStart);
    var pEnd = this.getCoords_(xEnd, yEnd);

    this.currentPath_.push({type: arcType,
                           x: p.x,
                           y: p.y,
                           radius: aRadius,
                           xStart: pStart.x,
                           yStart: pStart.y,
                           xEnd: pEnd.x,
                           yEnd: pEnd.y});

  };

  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
  };

  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
    var oldPath = this.currentPath_;
    this.beginPath();

    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
    this.stroke();

    this.currentPath_ = oldPath;
  };

  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
    var oldPath = this.currentPath_;
    this.beginPath();

    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
    this.fill();

    this.currentPath_ = oldPath;
  };

  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
    var gradient = new CanvasGradient_('gradient');
    gradient.x0_ = aX0;
    gradient.y0_ = aY0;
    gradient.x1_ = aX1;
    gradient.y1_ = aY1;
    return gradient;
  };

  contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
                                                   aX1, aY1, aR1) {
    var gradient = new CanvasGradient_('gradientradial');
    gradient.x0_ = aX0;
    gradient.y0_ = aY0;
    gradient.r0_ = aR0;
    gradient.x1_ = aX1;
    gradient.y1_ = aY1;
    gradient.r1_ = aR1;
    return gradient;
  };

  contextPrototype.drawImage = function(image, var_args) {
    var dx, dy, dw, dh, sx, sy, sw, sh;

    // to find the original width we overide the width and height
    var oldRuntimeWidth = image.runtimeStyle.width;
    var oldRuntimeHeight = image.runtimeStyle.height;
    image.runtimeStyle.width = 'auto';
    image.runtimeStyle.height = 'auto';

    // get the original size
    var w = image.width;
    var h = image.height;

    // and remove overides
    image.runtimeStyle.width = oldRuntimeWidth;
    image.runtimeStyle.height = oldRuntimeHeight;

    if (arguments.length == 3) {
      dx = arguments[1];
      dy = arguments[2];
      sx = sy = 0;
      sw = dw = w;
      sh = dh = h;
    } else if (arguments.length == 5) {
      dx = arguments[1];
      dy = arguments[2];
      dw = arguments[3];
      dh = arguments[4];
      sx = sy = 0;
      sw = w;
      sh = h;
    } else if (arguments.length == 9) {
      sx = arguments[1];
      sy = arguments[2];
      sw = arguments[3];
      sh = arguments[4];
      dx = arguments[5];
      dy = arguments[6];
      dw = arguments[7];
      dh = arguments[8];
    } else {
      throw Error('Invalid number of arguments');
    }

    var d = this.getCoords_(dx, dy);

    var w2 = sw / 2;
    var h2 = sh / 2;

    var vmlStr = [];

    var W = 10;
    var H = 10;

    // For some reason that I've now forgotten, using divs didn't work
    vmlStr.push(' <g_vml_:group',
                ' coordsize="', Z * W, ',', Z * H, '"',
                ' coordorigin="0,0"' ,
                ' style="width:', W, 'px;height:', H, 'px;position:absolute;');

    // If filters are necessary (rotation exists), create them
    // filters are bog-slow, so only create them if abbsolutely necessary
    // The following check doesn't account for skews (which don't exist
    // in the canvas spec (yet) anyway.

    if (this.m_[0][0] != 1 || this.m_[0][1]) {
      var filter = [];

      // Note the 12/21 reversal
      filter.push('M11=', this.m_[0][0], ',',
                  'M12=', this.m_[1][0], ',',
                  'M21=', this.m_[0][1], ',',
                  'M22=', this.m_[1][1], ',',
                  'Dx=', mr(d.x / Z), ',',
                  'Dy=', mr(d.y / Z), '');

      // Bounding box calculation (need to minimize displayed area so that
      // filters don't waste time on unused pixels.
      var max = d;
      var c2 = this.getCoords_(dx + dw, dy);
      var c3 = this.getCoords_(dx, dy + dh);
      var c4 = this.getCoords_(dx + dw, dy + dh);

      max.x = m.max(max.x, c2.x, c3.x, c4.x);
      max.y = m.max(max.y, c2.y, c3.y, c4.y);

      vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
                  'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
                  filter.join(''), ", sizingmethod='clip');")
    } else {
      vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
    }

    vmlStr.push(' ">' ,
                '<g_vml_:image src="', image.src, '"',
                ' style="width:', Z * dw, 'px;',
                ' height:', Z * dh, 'px;"',
                ' cropleft="', sx / w, '"',
                ' croptop="', sy / h, '"',
                ' cropright="', (w - sx - sw) / w, '"',
                ' cropbottom="', (h - sy - sh) / h, '"',
                ' />',
                '</g_vml_:group>');

    this.element_.insertAdjacentHTML('BeforeEnd',
                                    vmlStr.join(''));
  };

  contextPrototype.stroke = function(aFill) {
    var lineStr = [];
    var lineOpen = false;
    var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
    var color = a.color;
    var opacity = a.alpha * this.globalAlpha;

    var W = 10;
    var H = 10;

    lineStr.push('<g_vml_:shape',
                 ' filled="', !!aFill, '"',
                 ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
                 ' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
                 ' stroked="', !aFill, '"',
                 ' path="');

    var newSeq = false;
    var min = {x: null, y: null};
    var max = {x: null, y: null};

    for (var i = 0; i < this.currentPath_.length; i++) {
      var p = this.currentPath_[i];
      var c;

      switch (p.type) {
        case 'moveTo':
          c = p;
          lineStr.push(' m ', mr(p.x), ',', mr(p.y));
          break;
        case 'lineTo':
          lineStr.push(' l ', mr(p.x), ',', mr(p.y));
          break;
        case 'close':
          lineStr.push(' x ');
          p = null;
          break;
        case 'bezierCurveTo':
          lineStr.push(' c ',
                       mr(p.cp1x), ',', mr(p.cp1y), ',',
                       mr(p.cp2x), ',', mr(p.cp2y), ',',
                       mr(p.x), ',', mr(p.y));
          break;
        case 'at':
        case 'wa':
          lineStr.push(' ', p.type, ' ',
                       mr(p.x - this.arcScaleX_ * p.radius), ',',
                       mr(p.y - this.arcScaleY_ * p.radius), ' ',
                       mr(p.x + this.arcScaleX_ * p.radius), ',',
                       mr(p.y + this.arcScaleY_ * p.radius), ' ',
                       mr(p.xStart), ',', mr(p.yStart), ' ',
                       mr(p.xEnd), ',', mr(p.yEnd));
          break;
      }


      // TODO: Following is broken for curves due to
      //       move to proper paths.

      // Figure out dimensions so we can do gradient fills
      // properly
      if (p) {
        if (min.x == null || p.x < min.x) {
          min.x = p.x;
        }
        if (max.x == null || p.x > max.x) {
          max.x = p.x;
        }
        if (min.y == null || p.y < min.y) {
          min.y = p.y;
        }
        if (max.y == null || p.y > max.y) {
          max.y = p.y;
        }
      }
    }
    lineStr.push(' ">');

    if (!aFill) {
      var lineWidth = this.lineScale_ * this.lineWidth;

      // VML cannot correctly render a line if the width is less than 1px.
      // In that case, we dilute the color to make the line look thinner.
      if (lineWidth < 1) {
        opacity *= lineWidth;
      }

      lineStr.push(
        '<g_vml_:stroke',
        ' opacity="', opacity, '"',
        ' joinstyle="', this.lineJoin, '"',
        ' miterlimit="', this.miterLimit, '"',
        ' endcap="', processLineCap(this.lineCap), '"',
        ' weight="', lineWidth, 'px"',
        ' color="', color, '" />'
      );
    } else if (typeof this.fillStyle == 'object') {
      var fillStyle = this.fillStyle;
      var angle = 0;
      var focus = {x: 0, y: 0};

      // additional offset
      var shift = 0;
      // scale factor for offset
      var expansion = 1;

      if (fillStyle.type_ == 'gradient') {
        var x0 = fillStyle.x0_ / this.arcScaleX_;
        var y0 = fillStyle.y0_ / this.arcScaleY_;
        var x1 = fillStyle.x1_ / this.arcScaleX_;
        var y1 = fillStyle.y1_ / this.arcScaleY_;
        var p0 = this.getCoords_(x0, y0);
        var p1 = this.getCoords_(x1, y1);
        var dx = p1.x - p0.x;
        var dy = p1.y - p0.y;
        angle = Math.atan2(dx, dy) * 180 / Math.PI;

        // The angle should be a non-negative number.
        if (angle < 0) {
          angle += 360;
        }

        // Very small angles produce an unexpected result because they are
        // converted to a scientific notation string.
        if (angle < 1e-6) {
          angle = 0;
        }
      } else {
        var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);
        var width  = max.x - min.x;
        var height = max.y - min.y;
        focus = {
          x: (p0.x - min.x) / width,
          y: (p0.y - min.y) / height
        };

        width  /= this.arcScaleX_ * Z;
        height /= this.arcScaleY_ * Z;
        var dimension = m.max(width, height);
        shift = 2 * fillStyle.r0_ / dimension;
        expansion = 2 * fillStyle.r1_ / dimension - shift;
      }

      // We need to sort the color stops in ascending order by offset,
      // otherwise IE won't interpret it correctly.
      var stops = fillStyle.colors_;
      stops.sort(function(cs1, cs2) {
        return cs1.offset - cs2.offset;
      });

      var length = stops.length;
      var color1 = stops[0].color;
      var color2 = stops[length - 1].color;
      var opacity1 = stops[0].alpha * this.globalAlpha;
      var opacity2 = stops[length - 1].alpha * this.globalAlpha;

      var colors = [];
      for (var i = 0; i < length; i++) {
        var stop = stops[i];
        colors.push(stop.offset * expansion + shift + ' ' + stop.color);
      }

      // When colors attribute is used, the meanings of opacity and o:opacity2
      // are reversed.
      lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
                   ' method="none" focus="100%"',
                   ' color="', color1, '"',
                   ' color2="', color2, '"',
                   ' colors="', colors.join(','), '"',
                   ' opacity="', opacity2, '"',
                   ' g_o_:opacity2="', opacity1, '"',
                   ' angle="', angle, '"',
                   ' focusposition="', focus.x, ',', focus.y, '" />');
    } else {
      lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
                   '" />');
    }

    lineStr.push('</g_vml_:shape>');

    this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
  };

  contextPrototype.fill = function() {
    this.stroke(true);
  }

  contextPrototype.closePath = function() {
    this.currentPath_.push({type: 'close'});
  };

  /**
   * @private
   */
  contextPrototype.getCoords_ = function(aX, aY) {
    var m = this.m_;
    return {
      x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
      y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
    }
  };

  contextPrototype.save = function() {
    var o = {};
    copyState(this, o);
    this.aStack_.push(o);
    this.mStack_.push(this.m_);
    this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
  };

  contextPrototype.restore = function() {
    copyState(this.aStack_.pop(), this);
    this.m_ = this.mStack_.pop();
  };

  function matrixIsFinite(m) {
    for (var j = 0; j < 3; j++) {
      for (var k = 0; k < 2; k++) {
        if (!isFinite(m[j][k]) || isNaN(m[j][k])) {
          return false;
        }
      }
    }
    return true;
  }

  function setM(ctx, m, updateLineScale) {
    if (!matrixIsFinite(m)) {
      return;
    }
    ctx.m_ = m;

    if (updateLineScale) {
      // Get the line scale.
      // Determinant of this.m_ means how much the area is enlarged by the
      // transformation. So its square root can be used as a scale factor
      // for width.
      var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
      ctx.lineScale_ = sqrt(abs(det));
    }
  }

  contextPrototype.translate = function(aX, aY) {
    var m1 = [
      [1,  0,  0],
      [0,  1,  0],
      [aX, aY, 1]
    ];

    setM(this, matrixMultiply(m1, this.m_), false);
  };

  contextPrototype.rotate = function(aRot) {
    var c = mc(aRot);
    var s = ms(aRot);

    var m1 = [
      [c,  s, 0],
      [-s, c, 0],
      [0,  0, 1]
    ];

    setM(this, matrixMultiply(m1, this.m_), false);
  };

  contextPrototype.scale = function(aX, aY) {
    this.arcScaleX_ *= aX;
    this.arcScaleY_ *= aY;
    var m1 = [
      [aX, 0,  0],
      [0,  aY, 0],
      [0,  0,  1]
    ];

    setM(this, matrixMultiply(m1, this.m_), true);
  };

  contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
    var m1 = [
      [m11, m12, 0],
      [m21, m22, 0],
      [dx,  dy,  1]
    ];

    setM(this, matrixMultiply(m1, this.m_), true);
  };

  contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
    var m = [
      [m11, m12, 0],
      [m21, m22, 0],
      [dx,  dy,  1]
    ];

    setM(this, m, true);
  };

  /******** STUBS ********/
  contextPrototype.clip = function() {
    // TODO: Implement
  };

  contextPrototype.arcTo = function() {
    // TODO: Implement
  };

  contextPrototype.createPattern = function() {
    return new CanvasPattern_;
  };

  // Gradient / Pattern Stubs
  function CanvasGradient_(aType) {
    this.type_ = aType;
    this.x0_ = 0;
    this.y0_ = 0;
    this.r0_ = 0;
    this.x1_ = 0;
    this.y1_ = 0;
    this.r1_ = 0;
    this.colors_ = [];
  }

  CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
    aColor = processStyle(aColor);
    this.colors_.push({offset: aOffset,
                       color: aColor.color,
                       alpha: aColor.alpha});
  };

  function CanvasPattern_() {}

  // set up externs
  G_vmlCanvasManager = G_vmlCanvasManager_;
  CanvasRenderingContext2D = CanvasRenderingContext2D_;
  CanvasGradient = CanvasGradient_;
  CanvasPattern = CanvasPattern_;

})();

} // if

/*!

 handlebars v2.0.0

Copyright (C) 2011-2014 by Yehuda Katz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@license
*/
/* exported Handlebars */
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory();
  } else {
    root.Handlebars = root.Handlebars || factory();
  }
}(this, function () {
// handlebars/safe-string.js
var __module3__ = (function() {
  "use strict";
  var __exports__;
  // Build out our basic SafeString type
  function SafeString(string) {
    this.string = string;
  }

  SafeString.prototype.toString = function() {
    return "" + this.string;
  };

  __exports__ = SafeString;
  return __exports__;
})();

// handlebars/utils.js
var __module2__ = (function(__dependency1__) {
  "use strict";
  var __exports__ = {};
  /*jshint -W004 */
  var SafeString = __dependency1__;

  var escape = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': "&quot;",
    "'": "&#x27;",
    "`": "&#x60;"
  };

  var badChars = /[&<>"'`]/g;
  var possible = /[&<>"'`]/;

  function escapeChar(chr) {
    return escape[chr];
  }

  function extend(obj /* , ...source */) {
    for (var i = 1; i < arguments.length; i++) {
      for (var key in arguments[i]) {
        if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
          obj[key] = arguments[i][key];
        }
      }
    }

    return obj;
  }

  __exports__.extend = extend;var toString = Object.prototype.toString;
  __exports__.toString = toString;
  // Sourced from lodash
  // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
  var isFunction = function(value) {
    return typeof value === 'function';
  };
  // fallback for older versions of Chrome and Safari
  /* istanbul ignore next */
  if (isFunction(/x/)) {
    isFunction = function(value) {
      return typeof value === 'function' && toString.call(value) === '[object Function]';
    };
  }
  var isFunction;
  __exports__.isFunction = isFunction;
  /* istanbul ignore next */
  var isArray = Array.isArray || function(value) {
    return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;
  };
  __exports__.isArray = isArray;

  function escapeExpression(string) {
    // don't escape SafeStrings, since they're already safe
    if (string instanceof SafeString) {
      return string.toString();
    } else if (string == null) {
      return "";
    } else if (!string) {
      return string + '';
    }

    // Force a string conversion as this will be done by the append regardless and
    // the regex test will do this transparently behind the scenes, causing issues if
    // an object's to string has escaped characters in it.
    string = "" + string;

    if(!possible.test(string)) { return string; }
    return string.replace(badChars, escapeChar);
  }

  __exports__.escapeExpression = escapeExpression;function isEmpty(value) {
    if (!value && value !== 0) {
      return true;
    } else if (isArray(value) && value.length === 0) {
      return true;
    } else {
      return false;
    }
  }

  __exports__.isEmpty = isEmpty;function appendContextPath(contextPath, id) {
    return (contextPath ? contextPath + '.' : '') + id;
  }

  __exports__.appendContextPath = appendContextPath;
  return __exports__;
})(__module3__);

// handlebars/exception.js
var __module4__ = (function() {
  "use strict";
  var __exports__;

  var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];

  function Exception(message, node) {
    var line;
    if (node && node.firstLine) {
      line = node.firstLine;

      message += ' - ' + line + ':' + node.firstColumn;
    }

    var tmp = Error.prototype.constructor.call(this, message);

    // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
    for (var idx = 0; idx < errorProps.length; idx++) {
      this[errorProps[idx]] = tmp[errorProps[idx]];
    }

    if (line) {
      this.lineNumber = line;
      this.column = node.firstColumn;
    }
  }

  Exception.prototype = new Error();

  __exports__ = Exception;
  return __exports__;
})();

// handlebars/base.js
var __module1__ = (function(__dependency1__, __dependency2__) {
  "use strict";
  var __exports__ = {};
  var Utils = __dependency1__;
  var Exception = __dependency2__;

  var VERSION = "2.0.0";
  __exports__.VERSION = VERSION;var COMPILER_REVISION = 6;
  __exports__.COMPILER_REVISION = COMPILER_REVISION;
  var REVISION_CHANGES = {
    1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
    2: '== 1.0.0-rc.3',
    3: '== 1.0.0-rc.4',
    4: '== 1.x.x',
    5: '== 2.0.0-alpha.x',
    6: '>= 2.0.0-beta.1'
  };
  __exports__.REVISION_CHANGES = REVISION_CHANGES;
  var isArray = Utils.isArray,
      isFunction = Utils.isFunction,
      toString = Utils.toString,
      objectType = '[object Object]';

  function HandlebarsEnvironment(helpers, partials) {
    this.helpers = helpers || {};
    this.partials = partials || {};

    registerDefaultHelpers(this);
  }

  __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = {
    constructor: HandlebarsEnvironment,

    logger: logger,
    log: log,

    registerHelper: function(name, fn) {
      if (toString.call(name) === objectType) {
        if (fn) { throw new Exception('Arg not supported with multiple helpers'); }
        Utils.extend(this.helpers, name);
      } else {
        this.helpers[name] = fn;
      }
    },
    unregisterHelper: function(name) {
      delete this.helpers[name];
    },

    registerPartial: function(name, partial) {
      if (toString.call(name) === objectType) {
        Utils.extend(this.partials,  name);
      } else {
        this.partials[name] = partial;
      }
    },
    unregisterPartial: function(name) {
      delete this.partials[name];
    }
  };

  function registerDefaultHelpers(instance) {
    instance.registerHelper('helperMissing', function(/* [args, ]options */) {
      if(arguments.length === 1) {
        // A missing field in a {{foo}} constuct.
        return undefined;
      } else {
        // Someone is actually trying to call something, blow up.
        throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'");
      }
    });

    instance.registerHelper('blockHelperMissing', function(context, options) {
      var inverse = options.inverse,
          fn = options.fn;

      if(context === true) {
        return fn(this);
      } else if(context === false || context == null) {
        return inverse(this);
      } else if (isArray(context)) {
        if(context.length > 0) {
          if (options.ids) {
            options.ids = [options.name];
          }

          return instance.helpers.each(context, options);
        } else {
          return inverse(this);
        }
      } else {
        if (options.data && options.ids) {
          var data = createFrame(options.data);
          data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name);
          options = {data: data};
        }

        return fn(context, options);
      }
    });

    instance.registerHelper('each', function(context, options) {
      if (!options) {
        throw new Exception('Must pass iterator to #each');
      }

      var fn = options.fn, inverse = options.inverse;
      var i = 0, ret = "", data;

      var contextPath;
      if (options.data && options.ids) {
        contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.';
      }

      if (isFunction(context)) { context = context.call(this); }

      if (options.data) {
        data = createFrame(options.data);
      }

      if(context && typeof context === 'object') {
        if (isArray(context)) {
          for(var j = context.length; i<j; i++) {
            if (data) {
              data.index = i;
              data.first = (i === 0);
              data.last  = (i === (context.length-1));

              if (contextPath) {
                data.contextPath = contextPath + i;
              }
            }
            ret = ret + fn(context[i], { data: data });
          }
        } else {
          for(var key in context) {
            if(context.hasOwnProperty(key)) {
              if(data) {
                data.key = key;
                data.index = i;
                data.first = (i === 0);

                if (contextPath) {
                  data.contextPath = contextPath + key;
                }
              }
              ret = ret + fn(context[key], {data: data});
              i++;
            }
          }
        }
      }

      if(i === 0){
        ret = inverse(this);
      }

      return ret;
    });

    instance.registerHelper('if', function(conditional, options) {
      if (isFunction(conditional)) { conditional = conditional.call(this); }

      // Default behavior is to render the positive path if the value is truthy and not empty.
      // The `includeZero` option may be set to treat the condtional as purely not empty based on the
      // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
      if ((!options.hash.includeZero && !conditional) || Utils.isEmpty(conditional)) {
        return options.inverse(this);
      } else {
        return options.fn(this);
      }
    });

    instance.registerHelper('unless', function(conditional, options) {
      return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash});
    });

    instance.registerHelper('with', function(context, options) {
      if (isFunction(context)) { context = context.call(this); }

      var fn = options.fn;

      if (!Utils.isEmpty(context)) {
        if (options.data && options.ids) {
          var data = createFrame(options.data);
          data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]);
          options = {data:data};
        }

        return fn(context, options);
      } else {
        return options.inverse(this);
      }
    });

    instance.registerHelper('log', function(message, options) {
      var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
      instance.log(level, message);
    });

    instance.registerHelper('lookup', function(obj, field) {
      return obj && obj[field];
    });
  }

  var logger = {
    methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },

    // State enum
    DEBUG: 0,
    INFO: 1,
    WARN: 2,
    ERROR: 3,
    level: 3,

    // can be overridden in the host environment
    log: function(level, message) {
      if (logger.level <= level) {
        var method = logger.methodMap[level];
        if (typeof console !== 'undefined' && console[method]) {
          console[method].call(console, message);
        }
      }
    }
  };
  __exports__.logger = logger;
  var log = logger.log;
  __exports__.log = log;
  var createFrame = function(object) {
    var frame = Utils.extend({}, object);
    frame._parent = object;
    return frame;
  };
  __exports__.createFrame = createFrame;
  return __exports__;
})(__module2__, __module4__);

// handlebars/runtime.js
var __module5__ = (function(__dependency1__, __dependency2__, __dependency3__) {
  "use strict";
  var __exports__ = {};
  var Utils = __dependency1__;
  var Exception = __dependency2__;
  var COMPILER_REVISION = __dependency3__.COMPILER_REVISION;
  var REVISION_CHANGES = __dependency3__.REVISION_CHANGES;
  var createFrame = __dependency3__.createFrame;

  function checkRevision(compilerInfo) {
    var compilerRevision = compilerInfo && compilerInfo[0] || 1,
        currentRevision = COMPILER_REVISION;

    if (compilerRevision !== currentRevision) {
      if (compilerRevision < currentRevision) {
        var runtimeVersions = REVISION_CHANGES[currentRevision],
            compilerVersions = REVISION_CHANGES[compilerRevision];
        throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+
              "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").");
      } else {
        // Use the embedded version info since the runtime doesn't know about this revision yet
        throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+
              "Please update your runtime to a newer version ("+compilerInfo[1]+").");
      }
    }
  }

  __exports__.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial

  function template(templateSpec, env) {
    /* istanbul ignore next */
    if (!env) {
      throw new Exception("No environment passed to template");
    }
    if (!templateSpec || !templateSpec.main) {
      throw new Exception('Unknown template object: ' + typeof templateSpec);
    }

    // Note: Using env.VM references rather than local var references throughout this section to allow
    // for external users to override these as psuedo-supported APIs.
    env.VM.checkRevision(templateSpec.compiler);

    var invokePartialWrapper = function(partial, indent, name, context, hash, helpers, partials, data, depths) {
      if (hash) {
        context = Utils.extend({}, context, hash);
      }

      var result = env.VM.invokePartial.call(this, partial, name, context, helpers, partials, data, depths);

      if (result == null && env.compile) {
        var options = { helpers: helpers, partials: partials, data: data, depths: depths };
        partials[name] = env.compile(partial, { data: data !== undefined, compat: templateSpec.compat }, env);
        result = partials[name](context, options);
      }
      if (result != null) {
        if (indent) {
          var lines = result.split('\n');
          for (var i = 0, l = lines.length; i < l; i++) {
            if (!lines[i] && i + 1 === l) {
              break;
            }

            lines[i] = indent + lines[i];
          }
          result = lines.join('\n');
        }
        return result;
      } else {
        throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
      }
    };

    // Just add water
    var container = {
      lookup: function(depths, name) {
        var len = depths.length;
        for (var i = 0; i < len; i++) {
          if (depths[i] && depths[i][name] != null) {
            return depths[i][name];
          }
        }
      },
      lambda: function(current, context) {
        return typeof current === 'function' ? current.call(context) : current;
      },

      escapeExpression: Utils.escapeExpression,
      invokePartial: invokePartialWrapper,

      fn: function(i) {
        return templateSpec[i];
      },

      programs: [],
      program: function(i, data, depths) {
        var programWrapper = this.programs[i],
            fn = this.fn(i);
        if (data || depths) {
          programWrapper = program(this, i, fn, data, depths);
        } else if (!programWrapper) {
          programWrapper = this.programs[i] = program(this, i, fn);
        }
        return programWrapper;
      },

      data: function(data, depth) {
        while (data && depth--) {
          data = data._parent;
        }
        return data;
      },
      merge: function(param, common) {
        var ret = param || common;

        if (param && common && (param !== common)) {
          ret = Utils.extend({}, common, param);
        }

        return ret;
      },

      noop: env.VM.noop,
      compilerInfo: templateSpec.compiler
    };

    var ret = function(context, options) {
      options = options || {};
      var data = options.data;

      ret._setup(options);
      if (!options.partial && templateSpec.useData) {
        data = initData(context, data);
      }
      var depths;
      if (templateSpec.useDepths) {
        depths = options.depths ? [context].concat(options.depths) : [context];
      }

      return templateSpec.main.call(container, context, container.helpers, container.partials, data, depths);
    };
    ret.isTop = true;

    ret._setup = function(options) {
      if (!options.partial) {
        container.helpers = container.merge(options.helpers, env.helpers);

        if (templateSpec.usePartial) {
          container.partials = container.merge(options.partials, env.partials);
        }
      } else {
        container.helpers = options.helpers;
        container.partials = options.partials;
      }
    };

    ret._child = function(i, data, depths) {
      if (templateSpec.useDepths && !depths) {
        throw new Exception('must pass parent depths');
      }

      return program(container, i, templateSpec[i], data, depths);
    };
    return ret;
  }

  __exports__.template = template;function program(container, i, fn, data, depths) {
    var prog = function(context, options) {
      options = options || {};

      return fn.call(container, context, container.helpers, container.partials, options.data || data, depths && [context].concat(depths));
    };
    prog.program = i;
    prog.depth = depths ? depths.length : 0;
    return prog;
  }

  __exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data, depths) {
    var options = { partial: true, helpers: helpers, partials: partials, data: data, depths: depths };

    if(partial === undefined) {
      throw new Exception("The partial " + name + " could not be found");
    } else if(partial instanceof Function) {
      return partial(context, options);
    }
  }

  __exports__.invokePartial = invokePartial;function noop() { return ""; }

  __exports__.noop = noop;function initData(context, data) {
    if (!data || !('root' in data)) {
      data = data ? createFrame(data) : {};
      data.root = context;
    }
    return data;
  }
  return __exports__;
})(__module2__, __module4__, __module1__);

// handlebars.runtime.js
var __module0__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) {
  "use strict";
  var __exports__;
  /*globals Handlebars: true */
  var base = __dependency1__;

  // Each of these augment the Handlebars object. No need to setup here.
  // (This is done to easily share code between commonjs and browse envs)
  var SafeString = __dependency2__;
  var Exception = __dependency3__;
  var Utils = __dependency4__;
  var runtime = __dependency5__;

  // For compatibility and usage outside of module systems, make the Handlebars object a namespace
  var create = function() {
    var hb = new base.HandlebarsEnvironment();

    Utils.extend(hb, base);
    hb.SafeString = SafeString;
    hb.Exception = Exception;
    hb.Utils = Utils;
    hb.escapeExpression = Utils.escapeExpression;

    hb.VM = runtime;
    hb.template = function(spec) {
      return runtime.template(spec, hb);
    };

    return hb;
  };

  var Handlebars = create();
  Handlebars.create = create;

  Handlebars['default'] = Handlebars;

  __exports__ = Handlebars;
  return __exports__;
})(__module1__, __module3__, __module4__, __module2__, __module5__);

  return __module0__;
}));

/* Modernizr 2.8.3 (Custom Build) | MIT & BSD
 * Build: http://modernizr.com/download/#-csscolumns-inlinesvg-svg-svgclippaths-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes
 */
;



window.Modernizr = (function( window, document, undefined ) {

    var version = '2.8.3',

    Modernizr = {},


    docElement = document.documentElement,

    mod = 'modernizr',
    modElem = document.createElement(mod),
    mStyle = modElem.style,

    inputElem  ,


    toString = {}.toString,

    prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),



    omPrefixes = 'Webkit Moz O ms',

    cssomPrefixes = omPrefixes.split(' '),

    domPrefixes = omPrefixes.toLowerCase().split(' '),

    ns = {'svg': 'http://www.w3.org/2000/svg'},

    tests = {},
    inputs = {},
    attrs = {},

    classes = [],

    slice = classes.slice,

    featureName, 


    injectElementWithStyles = function( rule, callback, nodes, testnames ) {

      var style, ret, node, docOverflow,
          div = document.createElement('div'),
                body = document.body,
                fakeBody = body || document.createElement('body');

      if ( parseInt(nodes, 10) ) {
                      while ( nodes-- ) {
              node = document.createElement('div');
              node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
              div.appendChild(node);
          }
      }

                style = ['&#173;','<style id="s', mod, '">', rule, '</style>'].join('');
      div.id = mod;
          (body ? div : fakeBody).innerHTML += style;
      fakeBody.appendChild(div);
      if ( !body ) {
                fakeBody.style.background = '';
                fakeBody.style.overflow = 'hidden';
          docOverflow = docElement.style.overflow;
          docElement.style.overflow = 'hidden';
          docElement.appendChild(fakeBody);
      }

      ret = callback(div, rule);
        if ( !body ) {
          fakeBody.parentNode.removeChild(fakeBody);
          docElement.style.overflow = docOverflow;
      } else {
          div.parentNode.removeChild(div);
      }

      return !!ret;

    },



    isEventSupported = (function() {

      var TAGNAMES = {
        'select': 'input', 'change': 'input',
        'submit': 'form', 'reset': 'form',
        'error': 'img', 'load': 'img', 'abort': 'img'
      };

      function isEventSupported( eventName, element ) {

        element = element || document.createElement(TAGNAMES[eventName] || 'div');
        eventName = 'on' + eventName;

            var isSupported = eventName in element;

        if ( !isSupported ) {
                if ( !element.setAttribute ) {
            element = document.createElement('div');
          }
          if ( element.setAttribute && element.removeAttribute ) {
            element.setAttribute(eventName, '');
            isSupported = is(element[eventName], 'function');

                    if ( !is(element[eventName], 'undefined') ) {
              element[eventName] = undefined;
            }
            element.removeAttribute(eventName);
          }
        }

        element = null;
        return isSupported;
      }
      return isEventSupported;
    })(),


    _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;

    if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
      hasOwnProp = function (object, property) {
        return _hasOwnProperty.call(object, property);
      };
    }
    else {
      hasOwnProp = function (object, property) { 
        return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
      };
    }


    if (!Function.prototype.bind) {
      Function.prototype.bind = function bind(that) {

        var target = this;

        if (typeof target != "function") {
            throw new TypeError();
        }

        var args = slice.call(arguments, 1),
            bound = function () {

            if (this instanceof bound) {

              var F = function(){};
              F.prototype = target.prototype;
              var self = new F();

              var result = target.apply(
                  self,
                  args.concat(slice.call(arguments))
              );
              if (Object(result) === result) {
                  return result;
              }
              return self;

            } else {

              return target.apply(
                  that,
                  args.concat(slice.call(arguments))
              );

            }

        };

        return bound;
      };
    }

    function setCss( str ) {
        mStyle.cssText = str;
    }

    function setCssAll( str1, str2 ) {
        return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
    }

    function is( obj, type ) {
        return typeof obj === type;
    }

    function contains( str, substr ) {
        return !!~('' + str).indexOf(substr);
    }

    function testProps( props, prefixed ) {
        for ( var i in props ) {
            var prop = props[i];
            if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
                return prefixed == 'pfx' ? prop : true;
            }
        }
        return false;
    }

    function testDOMProps( props, obj, elem ) {
        for ( var i in props ) {
            var item = obj[props[i]];
            if ( item !== undefined) {

                            if (elem === false) return props[i];

                            if (is(item, 'function')){
                                return item.bind(elem || obj);
                }

                            return item;
            }
        }
        return false;
    }

    function testPropsAll( prop, prefixed, elem ) {

        var ucProp  = prop.charAt(0).toUpperCase() + prop.slice(1),
            props   = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');

            if(is(prefixed, "string") || is(prefixed, "undefined")) {
          return testProps(props, prefixed);

            } else {
          props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
          return testDOMProps(props, prefixed, elem);
        }
    }

    tests['csscolumns'] = function() {
        return testPropsAll('columnCount');
    };



    tests['svg'] = function() {
        return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
    };

    tests['inlinesvg'] = function() {
      var div = document.createElement('div');
      div.innerHTML = '<svg/>';
      return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
    };



    tests['svgclippaths'] = function() {
        return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
    };

    for ( var feature in tests ) {
        if ( hasOwnProp(tests, feature) ) {
                                    featureName  = feature.toLowerCase();
            Modernizr[featureName] = tests[feature]();

            classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
        }
    }



     Modernizr.addTest = function ( feature, test ) {
       if ( typeof feature == 'object' ) {
         for ( var key in feature ) {
           if ( hasOwnProp( feature, key ) ) {
             Modernizr.addTest( key, feature[ key ] );
           }
         }
       } else {

         feature = feature.toLowerCase();

         if ( Modernizr[feature] !== undefined ) {
                                              return Modernizr;
         }

         test = typeof test == 'function' ? test() : test;

         if (typeof enableClasses !== "undefined" && enableClasses) {
           docElement.className += ' ' + (test ? '' : 'no-') + feature;
         }
         Modernizr[feature] = test;

       }

       return Modernizr; 
     };


    setCss('');
    modElem = inputElem = null;


    Modernizr._version      = version;

    Modernizr._prefixes     = prefixes;
    Modernizr._domPrefixes  = domPrefixes;
    Modernizr._cssomPrefixes  = cssomPrefixes;


    Modernizr.hasEvent      = isEventSupported;

    Modernizr.testProp      = function(prop){
        return testProps([prop]);
    };

    Modernizr.testAllProps  = testPropsAll;


    Modernizr.testStyles    = injectElementWithStyles;
    Modernizr.prefixed      = function(prop, obj, elem){
      if(!obj) {
        return testPropsAll(prop, 'pfx');
      } else {
            return testPropsAll(prop, obj, elem);
      }
    };



    return Modernizr;

})(this, this.document);
;
/**
 * CSS3 multicolumn polyfill for list elements for IE7-9
 * Distributes items evenly to floating elements (regardless of heights)
 *
 * usage example:
 *  if (!Modernizr.csscolumns) {
 *    $('.mycolumn-element').multicolumn();
 *  }
 *
 * v0.1
 * July 2013
 * Tobias Schmidt <tobias.schmidt@seitenbau.com>
 */



(function ( $, window, document, undefined ) {
  var pluginName = 'multicolumn',
     defaults = {
       columnGap : 15, //is converted into percent in relative mode
       columnCount: 'auto',
       wrapperClass : 'column-wrapper',
       hiddenClass : 'mc-hidden',
       mode: 'relative',
       childSelector: false
     };
  function Plugin( element, options ) {
     this.jse = element;
     this.element   = $(element);
     this.options   = $.extend( {}, defaults, options );
     this._defaults = defaults;
     this._name     = pluginName;
     this.init();
  }
  Plugin.prototype = {

    init : function() {
      this.doColumns();
      this.setResizeHandler();
    },

    doColumns : function($el) {
      var self = this;
      var $vel = typeof $el == 'undefined' ? this.element : $el;

      $vel.each(function() {
        var $el = $(this);

        // get column Count
        var columnCount;
        if(self.options.columnCount === 'auto') {
          columnCount = $el.css('column-count') ? $el.css('column-count') : $el[0].currentStyle.getAttribute('column-count'); //IE
        } else {
          columnCount = self.options.columnCount;
        }

        // check columns
        if(!columnCount || columnCount < 2) {
          self.destroy($el);
          return;
        }

        var gapWidth = self.options.columnGap,
          tagName = $el.prop('tagName'),
          classes = $el.attr('class'),
          listMarginLeft = $el.css('margin-left'),
          listMarginRight = $el.css('margin-right'),
          listMarginBottom = $el.css('margin-bottom'),
          listMarginTop = $el.css('margin-top'),
          listPaddingRight = $el.css('padding-right'),
          listPaddingLeft = $el.css('padding-left'),
          listPaddingBottom = $el.css('padding-bottom'),
          listPaddingTop = $el.css('padding-top'),
          $children = $el.children(self.options.childSelector);

        // calculate vars
        var perColumnItemCount  = Math.ceil( $children.length / columnCount ),
          containerWidth = $el.parent().outerWidth() - (parseInt(listPaddingLeft, 10) + parseInt(listPaddingRight,10)),
          columnWidth = (containerWidth - (gapWidth * (columnCount - 1))) / columnCount;

        if(self.options.mode == 'relative') {
          columnWidth = (columnWidth / containerWidth * 100) + '%';
          gapWidth = (gapWidth / containerWidth * 100) + '%';
        } else {
          containerWidth = Math.floor(containerWidth);
          columnWidth = Math.floor(columnWidth);
        }


        // define wrapper element
        var $wrapper = $('<div class="clearfix ' + self.options.wrapperClass + '"></div>')
          .css({
            'margin-left': listMarginLeft,
            'margin-right': listMarginRight,
            'margin-top': listMarginTop,
            'margin-bottom': listMarginBottom,
            'padding-right' : listPaddingRight,
            'padding-left' : listPaddingLeft,
            'padding-top' : listPaddingTop,
            'padding-bottom' : listPaddingBottom
          });

        // get wrapper element
        var $lists = $wrapper.clone();

        // fill each column with list elements
        for (var i = 0; i < columnCount; i++) {
          var columnMargin = i > 0 ? gapWidth : 0;
          var $listItems = $children.clone();
          var fromCount = parseInt((perColumnItemCount * i), 10);
          var toCount = parseInt((fromCount + perColumnItemCount), 10);
          $listItems = $listItems.slice(fromCount, toCount);

          var $list = $('<' + tagName + '/>')
            .css({
              'display': 'block',
              'float': 'left',
              'width': columnWidth,
              'margin-right': 0,
              'margin-left': columnMargin,
              'padding' : 0
            })
           .attr('class', classes);

          //wrap $lists with wrapper and uls
          $lists.append($list.append($listItems));
       };

        //insert new element, remove old
        $el.after($lists).hide().addClass(self.options.hiddenClass);

        /* FIX if there are memory leaks: cleanup the
         * cleanup element && eventhandlers
         * Note: I this case you cannot get the element back  
        $el.remove();
         */
      });
    },

    setResizeHandler : function() {
      var self = this;
      $(window).on('orientationchange pageshow resize', self.waitForFinalEvent(function(e) {
        var _self = self;
        self.element.each(function() {
          var $el = $(this);
          _self.destroy($el, _self.bind(_self.doColumns, [$el], _self));
        });
      })).trigger('resize');
    },

    waitForFinalEvent : function (func, timeout) {
      var timeoutID , timeout = timeout || 400;
      return function () {
        var scope = this , args = arguments;
        clearTimeout(timeoutID);
        timeoutID = setTimeout( function () {
          func.apply( scope , Array.prototype.slice.call( args ) );
        } , timeout );
      }
    },

    destroy : function ($el, callback) {
      $el.show().removeClass(this.options.hiddenClass);
      $el.next('.' + this.options.wrapperClass).remove();

      if (typeof callback == 'function') {
        callback.call();
      }
    },

    bind : function(fn, args, scope) {
      return function () {
        fn.apply(scope, args);
      };
    }

  };

  $.fn[pluginName] = function ( options ) {
    return this.each(function () {
      $.data(this, "plugin_" + pluginName, new Plugin( this, options ));
    });
  };

})( jQuery, window, document );



$(document).ready(function(){
  if (!Modernizr.csscolumns) {    
    $('.module-near-you .column').multicolumn();
  }
});
/*!
* Parsleyjs
* Guillaume Potier - <guillaume@wisembly.com>
* Version 2.0.6 - built Tue Dec 02 2014 17:12:12
* MIT Licensed
*
*/
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){"undefined"==typeof a&&"undefined"!=typeof window.jQuery&&(a=window.jQuery);var b={attr:function(a,b,c){var d,e={},f=this.msieversion(),g=new RegExp("^"+b,"i");if("undefined"==typeof a||"undefined"==typeof a[0])return{};for(var h in a[0].attributes)if(d=a[0].attributes[h],"undefined"!=typeof d&&null!==d&&(!f||f>=8||d.specified)&&g.test(d.name)){if("undefined"!=typeof c&&new RegExp(c+"$","i").test(d.name))return!0;e[this.camelize(d.name.replace(b,""))]=this.deserializeValue(d.value)}return"undefined"==typeof c?e:!1},setAttr:function(a,b,c,d){a[0].setAttribute(this.dasherize(b+c),String(d))},get:function(a,b){for(var c=0,d=(b||"").split(".");this.isObject(a)||this.isArray(a);)if(a=a[d[c++]],c===d.length)return a;return void 0},hash:function(a){return String(Math.random()).substring(2,a?a+2:9)},isArray:function(a){return"[object Array]"===Object.prototype.toString.call(a)},isObject:function(a){return a===Object(a)},deserializeValue:function(b){var c;try{return b?"true"==b||("false"==b?!1:"null"==b?null:isNaN(c=Number(b))?/^[\[\{]/.test(b)?a.parseJSON(b):b:c):b}catch(d){return b}},camelize:function(a){return a.replace(/-+(.)?/g,function(a,b){return b?b.toUpperCase():""})},dasherize:function(a){return a.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()},msieversion:function(){var a=window.navigator.userAgent,b=a.indexOf("MSIE ");return b>0||navigator.userAgent.match(/Trident.*rv\:11\./)?parseInt(a.substring(b+5,a.indexOf(".",b)),10):0}},c={namespace:"data-parsley-",inputs:"input, textarea, select",excluded:"input[type=button], input[type=submit], input[type=reset], input[type=hidden]",priorityEnabled:!0,uiEnabled:!0,validationThreshold:3,focus:"first",trigger:!1,errorClass:"parsley-error",successClass:"parsley-success",classHandler:function(){},errorsContainer:function(){},errorsWrapper:'<ul class="parsley-errors-list"></ul>',errorTemplate:"<li></li>"},d=function(){};d.prototype={asyncSupport:!1,actualizeOptions:function(){return this.options=this.OptionsFactory.get(this),this},validateThroughValidator:function(a,b,c){return window.ParsleyValidator.validate.apply(window.ParsleyValidator,[a,b,c])},subscribe:function(b,c){return a.listenTo(this,b.toLowerCase(),c),this},unsubscribe:function(b){return a.unsubscribeTo(this,b.toLowerCase()),this},reset:function(){if("ParsleyForm"!==this.__class__)return a.emit("parsley:field:reset",this);for(var b=0;b<this.fields.length;b++)a.emit("parsley:field:reset",this.fields[b]);a.emit("parsley:form:reset",this)},destroy:function(){if("ParsleyForm"!==this.__class__)return this.$element.removeData("Parsley"),this.$element.removeData("ParsleyFieldMultiple"),void a.emit("parsley:field:destroy",this);for(var b=0;b<this.fields.length;b++)this.fields[b].destroy();this.$element.removeData("Parsley"),a.emit("parsley:form:destroy",this)}};var e=function(){var a={},b=function(a){this.__class__="Validator",this.__version__="1.0.0",this.options=a||{},this.bindingKey=this.options.bindingKey||"_validatorjsConstraint"};b.prototype={constructor:b,validate:function(a,b,c){if("string"!=typeof a&&"object"!=typeof a)throw new Error("You must validate an object or a string");return"string"==typeof a||g(a)?this._validateString(a,b,c):this.isBinded(a)?this._validateBindedObject(a,b):this._validateObject(a,b,c)},bind:function(a,b){if("object"!=typeof a)throw new Error("Must bind a Constraint to an object");return a[this.bindingKey]=new c(b),this},unbind:function(a){return"undefined"==typeof a._validatorjsConstraint?this:(delete a[this.bindingKey],this)},isBinded:function(a){return"undefined"!=typeof a[this.bindingKey]},getBinded:function(a){return this.isBinded(a)?a[this.bindingKey]:null},_validateString:function(a,b,c){var f,h=[];g(b)||(b=[b]);for(var i=0;i<b.length;i++){if(!(b[i]instanceof e))throw new Error("You must give an Assert or an Asserts array to validate a string");f=b[i].check(a,c),f instanceof d&&h.push(f)}return h.length?h:!0},_validateObject:function(a,b,d){if("object"!=typeof b)throw new Error("You must give a constraint to validate an object");return b instanceof c?b.check(a,d):new c(b).check(a,d)},_validateBindedObject:function(a,b){return a[this.bindingKey].check(a,b)}},b.errorCode={must_be_a_string:"must_be_a_string",must_be_an_array:"must_be_an_array",must_be_a_number:"must_be_a_number",must_be_a_string_or_array:"must_be_a_string_or_array"};var c=function(a,b){if(this.__class__="Constraint",this.options=b||{},this.nodes={},a)try{this._bootstrap(a)}catch(c){throw new Error("Should give a valid mapping object to Constraint",c,a)}};c.prototype={constructor:c,check:function(a,b){var c,d={};for(var h in this.nodes){for(var i=!1,j=this.get(h),k=g(j)?j:[j],l=k.length-1;l>=0;l--)"Required"!==k[l].__class__||(i=k[l].requiresValidation(b));if(this.has(h,a)||this.options.strict||i)try{this.has(h,this.options.strict||i?a:void 0)||(new e).HaveProperty(h).validate(a),c=this._check(h,a[h],b),(g(c)&&c.length>0||!g(c)&&!f(c))&&(d[h]=c)}catch(m){d[h]=m}}return f(d)?!0:d},add:function(a,b){if(b instanceof e||g(b)&&b[0]instanceof e)return this.nodes[a]=b,this;if("object"==typeof b&&!g(b))return this.nodes[a]=b instanceof c?b:new c(b),this;throw new Error("Should give an Assert, an Asserts array, a Constraint",b)},has:function(a,b){return b="undefined"!=typeof b?b:this.nodes,"undefined"!=typeof b[a]},get:function(a,b){return this.has(a)?this.nodes[a]:b||null},remove:function(a){var b=[];for(var c in this.nodes)c!==a&&(b[c]=this.nodes[c]);return this.nodes=b,this},_bootstrap:function(a){if(a instanceof c)return this.nodes=a.nodes;for(var b in a)this.add(b,a[b])},_check:function(a,b,d){if(this.nodes[a]instanceof e)return this._checkAsserts(b,[this.nodes[a]],d);if(g(this.nodes[a]))return this._checkAsserts(b,this.nodes[a],d);if(this.nodes[a]instanceof c)return this.nodes[a].check(b,d);throw new Error("Invalid node",this.nodes[a])},_checkAsserts:function(a,b,c){for(var d,e=[],f=0;f<b.length;f++)d=b[f].check(a,c),"undefined"!=typeof d&&!0!==d&&e.push(d);return e}};var d=function(a,b,c){if(this.__class__="Violation",!(a instanceof e))throw new Error("Should give an assertion implementing the Assert interface");this.assert=a,this.value=b,"undefined"!=typeof c&&(this.violation=c)};d.prototype={show:function(){var a={assert:this.assert.__class__,value:this.value};return this.violation&&(a.violation=this.violation),a},__toString:function(){return"undefined"!=typeof this.violation&&(this.violation='", '+this.getViolation().constraint+" expected was "+this.getViolation().expected),this.assert.__class__+' assert failed for "'+this.value+this.violation||""},getViolation:function(){var a,b;for(a in this.violation)b=this.violation[a];return{constraint:a,expected:b}}};var e=function(a){this.__class__="Assert",this.__parentClass__=this.__class__,this.groups=[],"undefined"!=typeof a&&this.addGroup(a)};e.prototype={construct:e,requiresValidation:function(a){return a&&!this.hasGroup(a)?!1:!a&&this.hasGroups()?!1:!0},check:function(a,b){if(this.requiresValidation(b))try{return this.validate(a,b)}catch(c){return c}},hasGroup:function(a){return g(a)?this.hasOneOf(a):"Any"===a?!0:this.hasGroups()?-1!==this.groups.indexOf(a):"Default"===a},hasOneOf:function(a){for(var b=0;b<a.length;b++)if(this.hasGroup(a[b]))return!0;return!1},hasGroups:function(){return this.groups.length>0},addGroup:function(a){return g(a)?this.addGroups(a):(this.hasGroup(a)||this.groups.push(a),this)},removeGroup:function(a){for(var b=[],c=0;c<this.groups.length;c++)a!==this.groups[c]&&b.push(this.groups[c]);return this.groups=b,this},addGroups:function(a){for(var b=0;b<a.length;b++)this.addGroup(a[b]);return this},HaveProperty:function(a){return this.__class__="HaveProperty",this.node=a,this.validate=function(a){if("undefined"==typeof a[this.node])throw new d(this,a,{value:this.node});return!0},this},Blank:function(){return this.__class__="Blank",this.validate=function(a){if("string"!=typeof a)throw new d(this,a,{value:b.errorCode.must_be_a_string});if(""!==a.replace(/^\s+/g,"").replace(/\s+$/g,""))throw new d(this,a);return!0},this},Callback:function(a){if(this.__class__="Callback",this.arguments=Array.prototype.slice.call(arguments),1===this.arguments.length?this.arguments=[]:this.arguments.splice(0,1),"function"!=typeof a)throw new Error("Callback must be instanciated with a function");return this.fn=a,this.validate=function(a){var b=this.fn.apply(this,[a].concat(this.arguments));if(!0!==b)throw new d(this,a,{result:b});return!0},this},Choice:function(a){if(this.__class__="Choice",!g(a)&&"function"!=typeof a)throw new Error("Choice must be instanciated with an array or a function");return this.list=a,this.validate=function(a){for(var b="function"==typeof this.list?this.list():this.list,c=0;c<b.length;c++)if(a===b[c])return!0;throw new d(this,a,{choices:b})},this},Collection:function(a){return this.__class__="Collection",this.constraint="undefined"!=typeof a?a instanceof e?a:new c(a):!1,this.validate=function(a,c){var e,h=new b,i=0,j={},k=this.groups.length?this.groups:c;if(!g(a))throw new d(this,array,{value:b.errorCode.must_be_an_array});for(var l=0;l<a.length;l++)e=this.constraint?h.validate(a[l],this.constraint,k):h.validate(a[l],k),f(e)||(j[i]=e),i++;return f(j)?!0:j},this},Count:function(a){return this.__class__="Count",this.count=a,this.validate=function(a){if(!g(a))throw new d(this,a,{value:b.errorCode.must_be_an_array});var c="function"==typeof this.count?this.count(a):this.count;if(isNaN(Number(c)))throw new Error("Count must be a valid interger",c);if(c!==a.length)throw new d(this,a,{count:c});return!0},this},Email:function(){return this.__class__="Email",this.validate=function(a){var c=/^((([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;if("string"!=typeof a)throw new d(this,a,{value:b.errorCode.must_be_a_string});if(!c.test(a))throw new d(this,a);return!0},this},EqualTo:function(a){if(this.__class__="EqualTo","undefined"==typeof a)throw new Error("EqualTo must be instanciated with a value or a function");return this.reference=a,this.validate=function(a){var b="function"==typeof this.reference?this.reference(a):this.reference;if(b!==a)throw new d(this,a,{value:b});return!0},this},GreaterThan:function(a){if(this.__class__="GreaterThan","undefined"==typeof a)throw new Error("Should give a threshold value");return this.threshold=a,this.validate=function(a){if(""===a||isNaN(Number(a)))throw new d(this,a,{value:b.errorCode.must_be_a_number});if(this.threshold>=a)throw new d(this,a,{threshold:this.threshold});return!0},this},GreaterThanOrEqual:function(a){if(this.__class__="GreaterThanOrEqual","undefined"==typeof a)throw new Error("Should give a threshold value");return this.threshold=a,this.validate=function(a){if(""===a||isNaN(Number(a)))throw new d(this,a,{value:b.errorCode.must_be_a_number});if(this.threshold>a)throw new d(this,a,{threshold:this.threshold});return!0},this},InstanceOf:function(a){if(this.__class__="InstanceOf","undefined"==typeof a)throw new Error("InstanceOf must be instanciated with a value");return this.classRef=a,this.validate=function(a){if(!0!=a instanceof this.classRef)throw new d(this,a,{classRef:this.classRef});return!0},this},Length:function(a){if(this.__class__="Length",!a.min&&!a.max)throw new Error("Lenth assert must be instanciated with a { min: x, max: y } object");return this.min=a.min,this.max=a.max,this.validate=function(a){if("string"!=typeof a&&!g(a))throw new d(this,a,{value:b.errorCode.must_be_a_string_or_array});if("undefined"!=typeof this.min&&this.min===this.max&&a.length!==this.min)throw new d(this,a,{min:this.min,max:this.max});if("undefined"!=typeof this.max&&a.length>this.max)throw new d(this,a,{max:this.max});if("undefined"!=typeof this.min&&a.length<this.min)throw new d(this,a,{min:this.min});return!0},this},LessThan:function(a){if(this.__class__="LessThan","undefined"==typeof a)throw new Error("Should give a threshold value");return this.threshold=a,this.validate=function(a){if(""===a||isNaN(Number(a)))throw new d(this,a,{value:b.errorCode.must_be_a_number});if(this.threshold<=a)throw new d(this,a,{threshold:this.threshold});return!0},this},LessThanOrEqual:function(a){if(this.__class__="LessThanOrEqual","undefined"==typeof a)throw new Error("Should give a threshold value");return this.threshold=a,this.validate=function(a){if(""===a||isNaN(Number(a)))throw new d(this,a,{value:b.errorCode.must_be_a_number});if(this.threshold<a)throw new d(this,a,{threshold:this.threshold});return!0},this},NotNull:function(){return this.__class__="NotNull",this.validate=function(a){if(null===a||"undefined"==typeof a)throw new d(this,a);return!0},this},NotBlank:function(){return this.__class__="NotBlank",this.validate=function(a){if("string"!=typeof a)throw new d(this,a,{value:b.errorCode.must_be_a_string});if(""===a.replace(/^\s+/g,"").replace(/\s+$/g,""))throw new d(this,a);return!0},this},Null:function(){return this.__class__="Null",this.validate=function(a){if(null!==a)throw new d(this,a);return!0},this},Range:function(a,b){if(this.__class__="Range","undefined"==typeof a||"undefined"==typeof b)throw new Error("Range assert expects min and max values");return this.min=a,this.max=b,this.validate=function(a){try{return"string"==typeof a&&isNaN(Number(a))||g(a)?(new e).Length({min:this.min,max:this.max}).validate(a):(new e).GreaterThanOrEqual(this.min).validate(a)&&(new e).LessThanOrEqual(this.max).validate(a),!0}catch(b){throw new d(this,a,b.violation)}return!0},this},Regexp:function(a,c){if(this.__class__="Regexp","undefined"==typeof a)throw new Error("You must give a regexp");return this.regexp=a,this.flag=c||"",this.validate=function(a){if("string"!=typeof a)throw new d(this,a,{value:b.errorCode.must_be_a_string});if(!new RegExp(this.regexp,this.flag).test(a))throw new d(this,a,{regexp:this.regexp,flag:this.flag});return!0},this},Required:function(){return this.__class__="Required",this.validate=function(a){if("undefined"==typeof a)throw new d(this,a);try{"string"==typeof a?(new e).NotNull().validate(a)&&(new e).NotBlank().validate(a):!0===g(a)&&(new e).Length({min:1}).validate(a)}catch(b){throw new d(this,a)}return!0},this},Unique:function(a){return this.__class__="Unique","object"==typeof a&&(this.key=a.key),this.validate=function(a){var c,e=[];if(!g(a))throw new d(this,a,{value:b.errorCode.must_be_an_array});for(var f=0;f<a.length;f++)if(c="object"==typeof a[f]?a[f][this.key]:a[f],"undefined"!=typeof c){if(-1!==e.indexOf(c))throw new d(this,a,{value:c});e.push(c)}return!0},this}},a.Assert=e,a.Validator=b,a.Violation=d,a.Constraint=c,Array.prototype.indexOf||(Array.prototype.indexOf=function(a){if(null===this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=0;if(arguments.length>1&&(d=Number(arguments[1]),d!=d?d=0:0!==d&&1/0!=d&&d!=-1/0&&(d=(d>0||-1)*Math.floor(Math.abs(d)))),d>=c)return-1;for(var e=d>=0?d:Math.max(c-Math.abs(d),0);c>e;e++)if(e in b&&b[e]===a)return e;return-1});var f=function(a){for(var b in a)return!1;return!0},g=function(a){return"[object Array]"===Object.prototype.toString.call(a)};return"function"==typeof define&&define.amd?define("vendors/validator.js/dist/validator",[],function(){return a}):"undefined"!=typeof module&&module.exports?module.exports=a:window["undefined"!=typeof validatorjs_ns?validatorjs_ns:"Validator"]=a,a}();e="undefined"!=typeof e?e:"undefined"!=typeof module?module.exports:null;var f=function(a,b){this.__class__="ParsleyValidator",this.Validator=e,this.locale="en",this.init(a||{},b||{})};f.prototype={init:function(b,c){this.catalog=c;for(var d in b)this.addValidator(d,b[d].fn,b[d].priority,b[d].requirementsTransformer);a.emit("parsley:validator:init")},setLocale:function(a){if("undefined"==typeof this.catalog[a])throw new Error(a+" is not available in the catalog");return this.locale=a,this},addCatalog:function(a,b,c){return"object"==typeof b&&(this.catalog[a]=b),!0===c?this.setLocale(a):this},addMessage:function(a,b,c){return"undefined"==typeof this.catalog[a]&&(this.catalog[a]={}),this.catalog[a][b.toLowerCase()]=c,this},validate:function(){return(new this.Validator.Validator).validate.apply(new e.Validator,arguments)},addValidator:function(b,c,d,f){return this.validators[b.toLowerCase()]=function(b){return a.extend((new e.Assert).Callback(c,b),{priority:d,requirementsTransformer:f})},this},updateValidator:function(a,b,c,d){return this.addValidator(a,b,c,d)},removeValidator:function(a){return delete this.validators[a],this},getErrorMessage:function(a){var b;return b="type"===a.name?this.catalog[this.locale][a.name][a.requirements]:this.formatMessage(this.catalog[this.locale][a.name],a.requirements),""!==b?b:this.catalog[this.locale].defaultMessage},formatMessage:function(a,b){if("object"==typeof b){for(var c in b)a=this.formatMessage(a,b[c]);return a}return"string"==typeof a?a.replace(new RegExp("%s","i"),b):""},validators:{notblank:function(){return a.extend((new e.Assert).NotBlank(),{priority:2})},required:function(){return a.extend((new e.Assert).Required(),{priority:512})},type:function(b){var c;switch(b){case"email":c=(new e.Assert).Email();break;case"range":case"number":c=(new e.Assert).Regexp("^-?(?:\\d+|\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$");break;case"integer":c=(new e.Assert).Regexp("^-?\\d+$");break;case"digits":c=(new e.Assert).Regexp("^\\d+$");break;case"alphanum":c=(new e.Assert).Regexp("^\\w+$","i");break;case"url":c=(new e.Assert).Regexp("(https?:\\/\\/)?(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)","i");break;default:throw new Error("validator type `"+b+"` is not supported")}return a.extend(c,{priority:256})},pattern:function(b){var c="";return/^\/.*\/(?:[gimy]*)$/.test(b)&&(c=b.replace(/.*\/([gimy]*)$/,"$1"),b=b.replace(new RegExp("^/(.*?)/"+c+"$"),"$1")),a.extend((new e.Assert).Regexp(b,c),{priority:64})},minlength:function(b){return a.extend((new e.Assert).Length({min:b}),{priority:30,requirementsTransformer:function(){return"string"!=typeof b||isNaN(b)?b:parseInt(b,10)}})},maxlength:function(b){return a.extend((new e.Assert).Length({max:b}),{priority:30,requirementsTransformer:function(){return"string"!=typeof b||isNaN(b)?b:parseInt(b,10)}})},length:function(b){return a.extend((new e.Assert).Length({min:b[0],max:b[1]}),{priority:32})},mincheck:function(a){return this.minlength(a)},maxcheck:function(a){return this.maxlength(a)},check:function(a){return this.length(a)},min:function(b){return a.extend((new e.Assert).GreaterThanOrEqual(b),{priority:30,requirementsTransformer:function(){return"string"!=typeof b||isNaN(b)?b:parseInt(b,10)}})},max:function(b){return a.extend((new e.Assert).LessThanOrEqual(b),{priority:30,requirementsTransformer:function(){return"string"!=typeof b||isNaN(b)?b:parseInt(b,10)}})},range:function(b){return a.extend((new e.Assert).Range(b[0],b[1]),{priority:32,requirementsTransformer:function(){for(var a=0;a<b.length;a++)b[a]="string"!=typeof b[a]||isNaN(b[a])?b[a]:parseInt(b[a],10);return b}})},equalto:function(b){return a.extend((new e.Assert).EqualTo(b),{priority:256,requirementsTransformer:function(){return a(b).length?a(b).val():b}})}}};var g=function(){this.__class__="ParsleyUI"};g.prototype={listen:function(){return a.listen("parsley:form:init",this,this.setupForm),a.listen("parsley:field:init",this,this.setupField),a.listen("parsley:field:validated",this,this.reflow),a.listen("parsley:form:validated",this,this.focus),a.listen("parsley:field:reset",this,this.reset),a.listen("parsley:form:destroy",this,this.destroy),a.listen("parsley:field:destroy",this,this.destroy),this},reflow:function(a){if("undefined"!=typeof a._ui&&!1!==a._ui.active){var b=this._diff(a.validationResult,a._ui.lastValidationResult);a._ui.lastValidationResult=a.validationResult,a._ui.validatedOnce=!0,this.manageStatusClass(a),this.manageErrorsMessages(a,b),this.actualizeTriggers(a),(b.kept.length||b.added.length)&&"undefined"==typeof a._ui.failedOnce&&this.manageFailingFieldTrigger(a)}},getErrorsMessages:function(a){if(!0===a.validationResult)return[];for(var b=[],c=0;c<a.validationResult.length;c++)b.push(this._getErrorMessage(a,a.validationResult[c].assert));return b},manageStatusClass:function(a){!0===a.validationResult?this._successClass(a):a.validationResult.length>0?this._errorClass(a):this._resetClass(a)},manageErrorsMessages:function(b,c){if("undefined"==typeof b.options.errorsMessagesDisabled){if("undefined"!=typeof b.options.errorMessage)return c.added.length||c.kept.length?(0===b._ui.$errorsWrapper.find(".parsley-custom-error-message").length&&b._ui.$errorsWrapper.append(a(b.options.errorTemplate).addClass("parsley-custom-error-message")),b._ui.$errorsWrapper.addClass("filled").find(".parsley-custom-error-message").html(b.options.errorMessage)):b._ui.$errorsWrapper.removeClass("filled").find(".parsley-custom-error-message").remove();for(var d=0;d<c.removed.length;d++)this.removeError(b,c.removed[d].assert.name,!0);for(d=0;d<c.added.length;d++)this.addError(b,c.added[d].assert.name,void 0,c.added[d].assert,!0);for(d=0;d<c.kept.length;d++)this.updateError(b,c.kept[d].assert.name,void 0,c.kept[d].assert,!0)}},addError:function(b,c,d,e,f){b._ui.$errorsWrapper.addClass("filled").append(a(b.options.errorTemplate).addClass("parsley-"+c).html(d||this._getErrorMessage(b,e))),!0!==f&&this._errorClass(b)},updateError:function(a,b,c,d,e){a._ui.$errorsWrapper.addClass("filled").find(".parsley-"+b).html(c||this._getErrorMessage(a,d)),!0!==e&&this._errorClass(a)},removeError:function(a,b,c){a._ui.$errorsWrapper.removeClass("filled").find(".parsley-"+b).remove(),!0!==c&&this.manageStatusClass(a)},focus:function(a){if(!0===a.validationResult||"none"===a.options.focus)return a._focusedField=null;a._focusedField=null;for(var b=0;b<a.fields.length;b++)if(!0!==a.fields[b].validationResult&&a.fields[b].validationResult.length>0&&"undefined"==typeof a.fields[b].options.noFocus){if("first"===a.options.focus)return a._focusedField=a.fields[b].$element,a._focusedField.focus();a._focusedField=a.fields[b].$element}return null===a._focusedField?null:a._focusedField.focus()},_getErrorMessage:function(a,b){var c=b.name+"Message";return"undefined"!=typeof a.options[c]?window.ParsleyValidator.formatMessage(a.options[c],b.requirements):window.ParsleyValidator.getErrorMessage(b)},_diff:function(a,b,c){for(var d=[],e=[],f=0;f<a.length;f++){for(var g=!1,h=0;h<b.length;h++)if(a[f].assert.name===b[h].assert.name){g=!0;break}g?e.push(a[f]):d.push(a[f])}return{kept:e,added:d,removed:c?[]:this._diff(b,a,!0).added}},setupForm:function(b){b.$element.on("submit.Parsley",!1,a.proxy(b.onSubmitValidate,b)),!1!==b.options.uiEnabled&&b.$element.attr("novalidate","")},setupField:function(b){var c={active:!1};!1!==b.options.uiEnabled&&(c.active=!0,b.$element.attr(b.options.namespace+"id",b.__id__),c.$errorClassHandler=this._manageClassHandler(b),c.errorsWrapperId="parsley-id-"+("undefined"!=typeof b.options.multiple?"multiple-"+b.options.multiple:b.__id__),c.$errorsWrapper=a(b.options.errorsWrapper).attr("id",c.errorsWrapperId),c.lastValidationResult=[],c.validatedOnce=!1,c.validationInformationVisible=!1,b._ui=c,b.$element.is(b.options.excluded)||this._insertErrorWrapper(b),this.actualizeTriggers(b))},_manageClassHandler:function(b){if("string"==typeof b.options.classHandler&&a(b.options.classHandler).length)return a(b.options.classHandler);var c=b.options.classHandler(b);return"undefined"!=typeof c&&c.length?c:"undefined"==typeof b.options.multiple||b.$element.is("select")?b.$element:b.$element.parent()},_insertErrorWrapper:function(b){var c;if("string"==typeof b.options.errorsContainer){if(a(b.options.errorsContainer).length)return a(b.options.errorsContainer).append(b._ui.$errorsWrapper);window.console&&window.console.warn&&window.console.warn("The errors container `"+b.options.errorsContainer+"` does not exist in DOM")}else"function"==typeof b.options.errorsContainer&&(c=b.options.errorsContainer(b));return"undefined"!=typeof c&&c.length?c.append(b._ui.$errorsWrapper):"undefined"==typeof b.options.multiple?b.$element.after(b._ui.$errorsWrapper):b.$element.parent().after(b._ui.$errorsWrapper)},actualizeTriggers:function(b){var c=this;if(b.options.multiple?a("["+b.options.namespace+'multiple="'+b.options.multiple+'"]').each(function(){a(this).off(".Parsley")}):b.$element.off(".Parsley"),!1!==b.options.trigger){var d=b.options.trigger.replace(/^\s+/g,"").replace(/\s+$/g,"");""!==d&&(b.options.multiple?a("["+b.options.namespace+'multiple="'+b.options.multiple+'"]').each(function(){a(this).on(d.split(" ").join(".Parsley ")+".Parsley",!1,a.proxy("function"==typeof b.eventValidate?b.eventValidate:c.eventValidate,b))}):b.$element.on(d.split(" ").join(".Parsley ")+".Parsley",!1,a.proxy("function"==typeof b.eventValidate?b.eventValidate:this.eventValidate,b)))}},eventValidate:function(a){new RegExp("key").test(a.type)&&!this._ui.validationInformationVisible&&this.getValue().length<=this.options.validationThreshold||(this._ui.validatedOnce=!0,this.validate())},manageFailingFieldTrigger:function(b){return b._ui.failedOnce=!0,b.options.multiple&&a("["+b.options.namespace+'multiple="'+b.options.multiple+'"]').each(function(){return new RegExp("change","i").test(a(this).parsley().options.trigger||"")?void 0:a(this).on("change.ParsleyFailedOnce",!1,a.proxy(b.validate,b))}),b.$element.is("select")&&!new RegExp("change","i").test(b.options.trigger||"")?b.$element.on("change.ParsleyFailedOnce",!1,a.proxy(b.validate,b)):new RegExp("keyup","i").test(b.options.trigger||"")?void 0:b.$element.on("keyup.ParsleyFailedOnce",!1,a.proxy(b.validate,b))},reset:function(a){a.$element.off(".Parsley"),a.$element.off(".ParsleyFailedOnce"),"undefined"!=typeof a._ui&&"ParsleyForm"!==a.__class__&&(a._ui.$errorsWrapper.removeClass("filled").children().remove(),this._resetClass(a),a._ui.validatedOnce=!1,a._ui.lastValidationResult=[],a._ui.validationInformationVisible=!1)},destroy:function(a){this.reset(a),"ParsleyForm"!==a.__class__&&("undefined"!=typeof a._ui&&a._ui.$errorsWrapper.remove(),delete a._ui)},_successClass:function(a){a._ui.validationInformationVisible=!0,a._ui.$errorClassHandler.removeClass(a.options.errorClass).addClass(a.options.successClass)},_errorClass:function(a){a._ui.validationInformationVisible=!0,a._ui.$errorClassHandler.removeClass(a.options.successClass).addClass(a.options.errorClass)},_resetClass:function(a){a._ui.$errorClassHandler.removeClass(a.options.successClass).removeClass(a.options.errorClass)}};var h=function(c,d,e,f){this.__class__="OptionsFactory",this.__id__=b.hash(4),this.formOptions=null,this.fieldOptions=null,this.staticOptions=a.extend(!0,{},c,d,e,{namespace:f})};h.prototype={get:function(a){if("undefined"==typeof a.__class__)throw new Error("Parsley Instance expected");switch(a.__class__){case"Parsley":return this.staticOptions;case"ParsleyForm":return this.getFormOptions(a);case"ParsleyField":case"ParsleyFieldMultiple":return this.getFieldOptions(a);default:throw new Error("Instance "+a.__class__+" is not supported")}},getFormOptions:function(c){return this.formOptions=b.attr(c.$element,this.staticOptions.namespace),a.extend({},this.staticOptions,this.formOptions)},getFieldOptions:function(c){return this.fieldOptions=b.attr(c.$element,this.staticOptions.namespace),null===this.formOptions&&"undefined"!=typeof c.parent&&(this.formOptions=this.getFormOptions(c.parent)),a.extend({},this.staticOptions,this.formOptions,this.fieldOptions)}};var i=function(c,d){if(this.__class__="ParsleyForm",this.__id__=b.hash(4),"OptionsFactory"!==b.get(d,"__class__"))throw new Error("You must give an OptionsFactory instance");this.OptionsFactory=d,this.$element=a(c),this.validationResult=null,this.options=this.OptionsFactory.get(this)};i.prototype={onSubmitValidate:function(b){return this.validate(void 0,void 0,b),!1===this.validationResult&&b instanceof a.Event&&(b.stopImmediatePropagation(),b.preventDefault()),this},validate:function(b,c,d){this.submitEvent=d,this.validationResult=!0;var e=[];this._refreshFields(),a.emit("parsley:form:validate",this);for(var f=0;f<this.fields.length;f++)(!b||this._isFieldInGroup(this.fields[f],b))&&(e=this.fields[f].validate(c),!0!==e&&e.length>0&&this.validationResult&&(this.validationResult=!1));return a.emit("parsley:form:validated",this),this.validationResult},isValid:function(a,b){this._refreshFields();for(var c=0;c<this.fields.length;c++)if((!a||this._isFieldInGroup(this.fields[c],a))&&!1===this.fields[c].isValid(b))return!1;return!0},_isFieldInGroup:function(c,d){return b.isArray(c.options.group)?-1!==a.inArray(d,c.options.group):c.options.group===d},_refreshFields:function(){return this.actualizeOptions()._bindFields()},_bindFields:function(){var a=this;return this.fields=[],this.fieldsMappedById={},this.$element.find(this.options.inputs).each(function(){var b=new window.Parsley(this,{},a);"ParsleyField"!==b.__class__&&"ParsleyFieldMultiple"!==b.__class__||b.$element.is(b.options.excluded)||"undefined"==typeof a.fieldsMappedById[b.__class__+"-"+b.__id__]&&(a.fieldsMappedById[b.__class__+"-"+b.__id__]=b,a.fields.push(b))}),this}};var j=function(c,d,e,f,g){if(!new RegExp("ParsleyField").test(b.get(c,"__class__")))throw new Error("ParsleyField or ParsleyFieldMultiple instance expected");if("function"!=typeof window.ParsleyValidator.validators[d]&&"Assert"!==window.ParsleyValidator.validators[d](e).__parentClass__)throw new Error("Valid validator expected");var h=function(a,c){return"undefined"!=typeof a.options[c+"Priority"]?a.options[c+"Priority"]:b.get(window.ParsleyValidator.validators[c](e),"priority")||2};return f=f||h(c,d),"function"==typeof window.ParsleyValidator.validators[d](e).requirementsTransformer&&(e=window.ParsleyValidator.validators[d](e).requirementsTransformer()),a.extend(window.ParsleyValidator.validators[d](e),{name:d,requirements:e,priority:f,groups:[f],isDomConstraint:g||b.attr(c.$element,c.options.namespace,d)})},k=function(c,d,e){this.__class__="ParsleyField",this.__id__=b.hash(4),this.$element=a(c),"undefined"!=typeof e?(this.parent=e,this.OptionsFactory=this.parent.OptionsFactory,this.options=this.OptionsFactory.get(this)):(this.OptionsFactory=d,this.options=this.OptionsFactory.get(this)),this.constraints=[],this.constraintsByName={},this.validationResult=[],this._bindConstraints()};k.prototype={validate:function(b){return this.value=this.getValue(),a.emit("parsley:field:validate",this),a.emit("parsley:field:"+(this.isValid(b,this.value)?"success":"error"),this),a.emit("parsley:field:validated",this),this.validationResult},isValid:function(a,b){this.refreshConstraints();var c=this._getConstraintsSortedPriorities();if(0===c.length)return this.validationResult=[];if(b=b||this.getValue(),!b.length&&!this._isRequired()&&"undefined"==typeof this.options.validateIfEmpty&&!0!==a)return this.validationResult=[];if(!1===this.options.priorityEnabled)return!0===(this.validationResult=this.validateThroughValidator(b,this.constraints,"Any"));for(var d=0;d<c.length;d++)if(!0!==(this.validationResult=this.validateThroughValidator(b,this.constraints,c[d])))return!1;
return!0},getValue:function(){var a;return a="undefined"!=typeof this.options.value?this.options.value:this.$element.val(),"undefined"==typeof a||null===a?"":!0===this.options.trimValue?a.replace(/^\s+|\s+$/g,""):a},refreshConstraints:function(){return this.actualizeOptions()._bindConstraints()},addConstraint:function(a,b,c,d){if(a=a.toLowerCase(),"function"==typeof window.ParsleyValidator.validators[a]){var e=new j(this,a,b,c,d);"undefined"!==this.constraintsByName[e.name]&&this.removeConstraint(e.name),this.constraints.push(e),this.constraintsByName[e.name]=e}return this},removeConstraint:function(a){for(var b=0;b<this.constraints.length;b++)if(a===this.constraints[b].name){this.constraints.splice(b,1);break}return delete this.constraintsByName[a],this},updateConstraint:function(a,b,c){return this.removeConstraint(a).addConstraint(a,b,c)},_bindConstraints:function(){for(var a=[],b={},c=0;c<this.constraints.length;c++)!1===this.constraints[c].isDomConstraint&&(a.push(this.constraints[c]),b[this.constraints[c].name]=this.constraints[c]);this.constraints=a,this.constraintsByName=b;for(var d in this.options)this.addConstraint(d,this.options[d]);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);var a=this.$element.attr("type");return"undefined"==typeof a?this:"number"===a?"undefined"==typeof this.$element.attr("step")||0===parseFloat(this.$element.attr("step"))%1?this.addConstraint("type","integer",void 0,!0):this.addConstraint("type","number",void 0,!0):new RegExp(a,"i").test("email url range")?this.addConstraint("type",a,void 0,!0):this},_isRequired:function(){return"undefined"==typeof this.constraintsByName.required?!1:!1!==this.constraintsByName.required.requirements},_getConstraintsSortedPriorities:function(){for(var a=[],b=0;b<this.constraints.length;b++)-1===a.indexOf(this.constraints[b].priority)&&a.push(this.constraints[b].priority);return a.sort(function(a,b){return b-a}),a}};var l=function(){this.__class__="ParsleyFieldMultiple"};l.prototype={addElement:function(a){return this.$elements.push(a),this},refreshConstraints:function(){var b;if(this.constraints=[],this.$element.is("select"))return this.actualizeOptions()._bindConstraints(),this;for(var c=0;c<this.$elements.length;c++)if(a("html").has(this.$elements[c]).length){b=this.$elements[c].data("ParsleyFieldMultiple").refreshConstraints().constraints;for(var d=0;d<b.length;d++)this.addConstraint(b[d].name,b[d].requirements,b[d].priority,b[d].isDomConstraint)}else this.$elements.splice(c,1);return this},getValue:function(){if("undefined"!=typeof this.options.value)return this.options.value;if(this.$element.is("input[type=radio]"))return a("["+this.options.namespace+'multiple="'+this.options.multiple+'"]:checked').val()||"";if(this.$element.is("input[type=checkbox]")){var b=[];return a("["+this.options.namespace+'multiple="'+this.options.multiple+'"]:checked').each(function(){b.push(a(this).val())}),b.length?b:[]}return this.$element.is("select")&&null===this.$element.val()?[]:this.$element.val()},_init:function(a){return this.$elements=[this.$element],this.options.multiple=a,this}};var m=a({}),n={};a.listen=function(a){if("undefined"==typeof n[a]&&(n[a]=[]),"function"==typeof arguments[1])return n[a].push({fn:arguments[1]});if("object"==typeof arguments[1]&&"function"==typeof arguments[2])return n[a].push({fn:arguments[2],ctxt:arguments[1]});throw new Error("Wrong parameters")},a.listenTo=function(a,b,c){if("undefined"==typeof n[b]&&(n[b]=[]),!(a instanceof k||a instanceof i))throw new Error("Must give Parsley instance");if("string"!=typeof b||"function"!=typeof c)throw new Error("Wrong parameters");n[b].push({instance:a,fn:c})},a.unsubscribe=function(a,b){if("undefined"!=typeof n[a]){if("string"!=typeof a||"function"!=typeof b)throw new Error("Wrong arguments");for(var c=0;c<n[a].length;c++)if(n[a][c].fn===b)return n[a].splice(c,1)}},a.unsubscribeTo=function(a,b){if("undefined"!=typeof n[b]){if(!(a instanceof k||a instanceof i))throw new Error("Must give Parsley instance");for(var c=0;c<n[b].length;c++)if("undefined"!=typeof n[b][c].instance&&n[b][c].instance.__id__===a.__id__)return n[b].splice(c,1)}},a.unsubscribeAll=function(a){"undefined"!=typeof n[a]&&delete n[a]},a.emit=function(a,b){if("undefined"!=typeof n[a])for(var c=0;c<n[a].length;c++)if("undefined"!=typeof n[a][c].instance){if(b instanceof k||b instanceof i)if(n[a][c].instance.__id__!==b.__id__){if(n[a][c].instance instanceof i&&b instanceof k)for(var d=0;d<n[a][c].instance.fields.length;d++)if(n[a][c].instance.fields[d].__id__===b.__id__){n[a][c].fn.apply(m,Array.prototype.slice.call(arguments,1));continue}}else n[a][c].fn.apply(m,Array.prototype.slice.call(arguments,1))}else n[a][c].fn.apply("undefined"!=typeof n[a][c].ctxt?n[a][c].ctxt:m,Array.prototype.slice.call(arguments,1))},a.subscribed=function(){return n},window.ParsleyConfig=window.ParsleyConfig||{},window.ParsleyConfig.i18n=window.ParsleyConfig.i18n||{},window.ParsleyConfig.i18n.en=a.extend(window.ParsleyConfig.i18n.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."}),"undefined"!=typeof window.ParsleyValidator&&window.ParsleyValidator.addCatalog("en",window.ParsleyConfig.i18n.en,!0);var o=function(c,d,e){if(this.__class__="Parsley",this.__version__="2.0.6",this.__id__=b.hash(4),"undefined"==typeof c)throw new Error("You must give an element");if("undefined"!=typeof e&&"ParsleyForm"!==e.__class__)throw new Error("Parent instance must be a ParsleyForm instance");return this.init(a(c),d,e)};o.prototype={init:function(a,d,e){if(!a.length)throw new Error("You must bind Parsley on an existing element.");if(this.$element=a,this.$element.data("Parsley")){var f=this.$element.data("Parsley");return"undefined"!=typeof e&&(f.parent=e),f}return this.OptionsFactory=new h(c,b.get(window,"ParsleyConfig")||{},d,this.getNamespace(d)),this.options=this.OptionsFactory.get(this),this.$element.is("form")||b.attr(this.$element,this.options.namespace,"validate")&&!this.$element.is(this.options.inputs)?this.bind("parsleyForm"):this.$element.is(this.options.inputs)&&!this.$element.is(this.options.excluded)?this.isMultiple()?this.handleMultiple(e):this.bind("parsleyField",e):this},isMultiple:function(){return this.$element.is("input[type=radio], input[type=checkbox]")&&"undefined"==typeof this.options.multiple||this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple")},handleMultiple:function(c){var d,e,f,g=this;if(this.options=a.extend(this.options,c?c.OptionsFactory.get(c):{},b.attr(this.$element,this.options.namespace)),this.options.multiple?e=this.options.multiple:"undefined"!=typeof this.$element.attr("name")&&this.$element.attr("name").length?e=d=this.$element.attr("name"):"undefined"!=typeof this.$element.attr("id")&&this.$element.attr("id").length&&(e=this.$element.attr("id")),this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple"))return this.bind("parsleyFieldMultiple",c,e||this.__id__);if("undefined"==typeof e)return window.console&&window.console.warn&&window.console.warn("To be binded by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.",this.$element),this;if(e=e.replace(/(:|\.|\[|\]|\{|\}|\$)/g,""),"undefined"!=typeof d&&a('input[name="'+d+'"]').each(function(){a(this).is("input[type=radio], input[type=checkbox]")&&a(this).attr(g.options.namespace+"multiple",e)}),a("["+this.options.namespace+"multiple="+e+"]").length)for(var h=0;h<a("["+this.options.namespace+"multiple="+e+"]").length;h++)if("undefined"!=typeof a(a("["+this.options.namespace+"multiple="+e+"]").get(h)).data("Parsley")){f=a(a("["+this.options.namespace+"multiple="+e+"]").get(h)).data("Parsley"),this.$element.data("ParsleyFieldMultiple")||(f.addElement(this.$element),this.$element.attr(this.options.namespace+"id",f.__id__));break}return this.bind("parsleyField",c,e,!0),f||this.bind("parsleyFieldMultiple",c,e)},getNamespace:function(a){return"undefined"!=typeof this.$element.data("parsleyNamespace")?this.$element.data("parsleyNamespace"):"undefined"!=typeof b.get(a,"namespace")?a.namespace:"undefined"!=typeof b.get(window,"ParsleyConfig.namespace")?window.ParsleyConfig.namespace:c.namespace},bind:function(c,e,f,g){var h;switch(c){case"parsleyForm":h=a.extend(new i(this.$element,this.OptionsFactory),new d,window.ParsleyExtend)._bindFields();break;case"parsleyField":h=a.extend(new k(this.$element,this.OptionsFactory,e),new d,window.ParsleyExtend);break;case"parsleyFieldMultiple":h=a.extend(new k(this.$element,this.OptionsFactory,e),new d,new l,window.ParsleyExtend)._init(f);break;default:throw new Error(c+"is not a supported Parsley type")}return"undefined"!=typeof f&&b.setAttr(this.$element,this.options.namespace,"multiple",f),"undefined"!=typeof g?(this.$element.data("ParsleyFieldMultiple",h),h):(new RegExp("ParsleyF","i").test(h.__class__)&&(this.$element.data("Parsley",h),a.emit("parsley:"+("parsleyForm"===c?"form":"field")+":init",h)),h)}},a.fn.parsley=a.fn.psly=function(b){if(this.length>1){var c=[];return this.each(function(){c.push(a(this).parsley(b))}),c}return a(this).length?new o(this,b):void(window.console&&window.console.warn&&window.console.warn("You must bind Parsley on an existing element."))},window.ParsleyUI="function"==typeof b.get(window,"ParsleyConfig.ParsleyUI")?(new window.ParsleyConfig.ParsleyUI).listen():(new g).listen(),"undefined"==typeof window.ParsleyExtend&&(window.ParsleyExtend={}),"undefined"==typeof window.ParsleyConfig&&(window.ParsleyConfig={}),window.Parsley=window.psly=o,window.ParsleyUtils=b,window.ParsleyValidator=new f(window.ParsleyConfig.validators,window.ParsleyConfig.i18n),!1!==b.get(window,"ParsleyConfig.autoBind")&&a(function(){a("[data-parsley-validate]").length&&a("[data-parsley-validate]").parsley()})});
/*!
 * The MIT License
 *
 * Copyright (c) 2012 James Allardice
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

( function ( global ) {

  'use strict';

  //
  // Test for support. We do this as early as possible to optimise for browsers
  // that have native support for the attribute.
  //

  var test = document.createElement('input');
  var nativeSupport = test.placeholder !== void 0;

  global.Placeholders = {
    nativeSupport: nativeSupport,
    disable: nativeSupport ? noop : disablePlaceholders,
    enable: nativeSupport ? noop : enablePlaceholders
  };

  if ( nativeSupport ) {
    return;
  }

  //
  // If we reach this point then the browser does not have native support for
  // the attribute.
  //

  // The list of input element types that support the placeholder attribute.
  var validTypes = [
    'text',
    'search',
    'url',
    'tel',
    'email',
    'password',
    'number',
    'textarea'
  ];

  // The list of keycodes that are not allowed when the polyfill is configured
  // to hide-on-input.
  var badKeys = [

    // The following keys all cause the caret to jump to the end of the input
    // value.

    27, // Escape
    33, // Page up
    34, // Page down
    35, // End
    36, // Home

    // Arrow keys allow you to move the caret manually, which should be
    // prevented when the placeholder is visible.

    37, // Left
    38, // Up
    39, // Right
    40, // Down

    // The following keys allow you to modify the placeholder text by removing
    // characters, which should be prevented when the placeholder is visible.

    8, // Backspace
    46 // Delete
  ];

  // Styling variables.
  var placeholderStyleColor = '#ccc';
  var placeholderClassName = 'placeholdersjs';
  var classNameRegExp = new RegExp('(?:^|\\s)' + placeholderClassName + '(?!\\S)');

  // The various data-* attributes used by the polyfill.
  var ATTR_CURRENT_VAL = 'data-placeholder-value';
  var ATTR_ACTIVE = 'data-placeholder-active';
  var ATTR_INPUT_TYPE = 'data-placeholder-type';
  var ATTR_FORM_HANDLED = 'data-placeholder-submit';
  var ATTR_EVENTS_BOUND = 'data-placeholder-bound';
  var ATTR_OPTION_FOCUS = 'data-placeholder-focus';
  var ATTR_OPTION_LIVE = 'data-placeholder-live';
  var ATTR_MAXLENGTH = 'data-placeholder-maxlength';

  // Various other variables used throughout the rest of the script.
  var UPDATE_INTERVAL = 100;
  var head = document.getElementsByTagName('head')[ 0 ];
  var root = document.documentElement;
  var Placeholders = global.Placeholders;
  var keydownVal;

  // Get references to all the input and textarea elements currently in the DOM
  // (live NodeList objects to we only need to do this once).
  var inputs = document.getElementsByTagName('input');
  var textareas = document.getElementsByTagName('textarea');

  // Get any settings declared as data-* attributes on the root element.
  // Currently the only options are whether to hide the placeholder on focus
  // or input and whether to auto-update.
  var hideOnInput = root.getAttribute(ATTR_OPTION_FOCUS) === 'false';
  var liveUpdates = root.getAttribute(ATTR_OPTION_LIVE) !== 'false';

  // Create style element for placeholder styles (instead of directly setting
  // style properties on elements - allows for better flexibility alongside
  // user-defined styles).
  var styleElem = document.createElement('style');
  styleElem.type = 'text/css';

  // Create style rules as text node.
  var styleRules = document.createTextNode(
    '.' + placeholderClassName + ' {' +
      'color:' + placeholderStyleColor + ';' +
    '}'
  );

  // Append style rules to newly created stylesheet.
  if ( styleElem.styleSheet ) {
    styleElem.styleSheet.cssText = styleRules.nodeValue;
  } else {
    styleElem.appendChild(styleRules);
  }

  // Prepend new style element to the head (before any existing stylesheets,
  // so user-defined rules take precedence).
  head.insertBefore(styleElem, head.firstChild);

  // Set up the placeholders.
  var placeholder;
  var elem;

  for ( var i = 0, len = inputs.length + textareas.length; i < len; i++ ) {

    // Find the next element. If we've already done all the inputs we move on
    // to the textareas.
    elem = i < inputs.length ? inputs[ i ] : textareas[ i - inputs.length ];

    // Get the value of the placeholder attribute, if any. IE10 emulating IE7
    // fails with getAttribute, hence the use of the attributes node.
    placeholder = elem.attributes.placeholder;

    // If the element has a placeholder attribute we need to modify it.
    if ( placeholder ) {

      // IE returns an empty object instead of undefined if the attribute is
      // not present.
      placeholder = placeholder.nodeValue;

      // Only apply the polyfill if this element is of a type that supports
      // placeholders and has a placeholder attribute with a non-empty value.
      if ( placeholder && inArray(validTypes, elem.type) ) {
        newElement(elem);
      }
    }
  }

  // If enabled, the polyfill will repeatedly check for changed/added elements
  // and apply to those as well.
  var timer = setInterval(function () {
    for ( var i = 0, len = inputs.length + textareas.length; i < len; i++ ) {
      elem = i < inputs.length ? inputs[ i ] : textareas[ i - inputs.length ];

      // Only apply the polyfill if this element is of a type that supports
      // placeholders, and has a placeholder attribute with a non-empty value.
      placeholder = elem.attributes.placeholder;

      if ( placeholder ) {

        placeholder = placeholder.nodeValue;

        if ( placeholder && inArray(validTypes, elem.type) ) {

          // If the element hasn't had event handlers bound to it then add
          // them.
          if ( !elem.getAttribute(ATTR_EVENTS_BOUND) ) {
            newElement(elem);
          }

          // If the placeholder value has changed or not been initialised yet
          // we need to update the display.
          if (
            placeholder !== elem.getAttribute(ATTR_CURRENT_VAL) ||
            ( elem.type === 'password' && !elem.getAttribute(ATTR_INPUT_TYPE) )
          ) {

            // Attempt to change the type of password inputs (fails in IE < 9).
            if (
              elem.type === 'password' &&
              !elem.getAttribute(ATTR_INPUT_TYPE) &&
              changeType(elem, 'text')
            ) {
              elem.setAttribute(ATTR_INPUT_TYPE, 'password');
            }

            // If the placeholder value has changed and the placeholder is
            // currently on display we need to change it.
            if ( elem.value === elem.getAttribute(ATTR_CURRENT_VAL) ) {
              elem.value = placeholder;
            }

            // Keep a reference to the current placeholder value in case it
            // changes via another script.
            elem.setAttribute(ATTR_CURRENT_VAL, placeholder);
          }
        }
      } else if ( elem.getAttribute(ATTR_ACTIVE) ) {
        hidePlaceholder(elem);
        elem.removeAttribute(ATTR_CURRENT_VAL);
      }
    }

    // If live updates are not enabled cancel the timer.
    if ( !liveUpdates ) {
      clearInterval(timer);
    }
  }, UPDATE_INTERVAL);

  // Disabling placeholders before unloading the page prevents flash of
  // unstyled placeholders on load if the page was refreshed.
  addEventListener(global, 'beforeunload', function () {
    Placeholders.disable();
  });

  //
  // Utility functions
  //

  // No-op (used in place of public methods when native support is detected).
  function noop() {}

  // Avoid IE9 activeElement of death when an iframe is used.
  //
  // More info:
  //  - http://bugs.jquery.com/ticket/13393
  //  - https://github.com/jquery/jquery/commit/85fc5878b3c6af73f42d61eedf73013e7faae408
  function safeActiveElement() {
    try {
      return document.activeElement;
    } catch ( err ) {}
  }

  // Check whether an item is in an array. We don't use Array.prototype.indexOf
  // so we don't clobber any existing polyfills. This is a really simple
  // alternative.
  function inArray( arr, item ) {
    for ( var i = 0, len = arr.length; i < len; i++ ) {
      if ( arr[ i ] === item ) {
        return true;
      }
    }
    return false;
  }

  // Cross-browser DOM event binding
  function addEventListener( elem, event, fn ) {
    if ( elem.addEventListener ) {
      return elem.addEventListener(event, fn, false);
    }
    if ( elem.attachEvent ) {
      return elem.attachEvent('on' + event, fn);
    }
  }

  // Move the caret to the index position specified. Assumes that the element
  // has focus.
  function moveCaret( elem, index ) {
    var range;
    if ( elem.createTextRange ) {
      range = elem.createTextRange();
      range.move('character', index);
      range.select();
    } else if ( elem.selectionStart ) {
      elem.focus();
      elem.setSelectionRange(index, index);
    }
  }

  // Attempt to change the type property of an input element.
  function changeType( elem, type ) {
    try {
      elem.type = type;
      return true;
    } catch ( e ) {
      // You can't change input type in IE8 and below.
      return false;
    }
  }

  function handleElem( node, callback ) {

    // Check if the passed in node is an input/textarea (in which case it can't
    // have any affected descendants).
    if ( node && node.getAttribute(ATTR_CURRENT_VAL) ) {
      callback(node);
    } else {

      // If an element was passed in, get all affected descendants. Otherwise,
      // get all affected elements in document.
      var handleInputs = node ? node.getElementsByTagName('input') : inputs;
      var handleTextareas = node ? node.getElementsByTagName('textarea') : textareas;

      var handleInputsLength = handleInputs ? handleInputs.length : 0;
      var handleTextareasLength = handleTextareas ? handleTextareas.length : 0;

      // Run the callback for each element.
      var len = handleInputsLength + handleTextareasLength;
      var elem;
      for ( var i = 0; i < len; i++ ) {

        elem = i < handleInputsLength ?
          handleInputs[ i ] :
          handleTextareas[ i - handleInputsLength ];

        callback(elem);
      }
    }
  }

  // Return all affected elements to their normal state (remove placeholder
  // value if present).
  function disablePlaceholders( node ) {
    handleElem(node, hidePlaceholder);
  }

  // Show the placeholder value on all appropriate elements.
  function enablePlaceholders( node ) {
    handleElem(node, showPlaceholder);
  }

  // Hide the placeholder value on a single element. Returns true if the
  // placeholder was hidden and false if it was not (because it wasn't visible
  // in the first place).
  function hidePlaceholder( elem, keydownValue ) {

    var valueChanged = !!keydownValue && elem.value !== keydownValue;
    var isPlaceholderValue = elem.value === elem.getAttribute(ATTR_CURRENT_VAL);

    if (
      ( valueChanged || isPlaceholderValue ) &&
      elem.getAttribute(ATTR_ACTIVE) === 'true'
    ) {

      elem.removeAttribute(ATTR_ACTIVE);
      elem.value = elem.value.replace(elem.getAttribute(ATTR_CURRENT_VAL), '');
      elem.className = elem.className.replace(classNameRegExp, '');

      // Restore the maxlength value. Old FF returns -1 if attribute not set.
      // See GH-56.
      var maxLength = elem.getAttribute(ATTR_MAXLENGTH);
      if ( parseInt(maxLength, 10) >= 0 ) {
        elem.setAttribute('maxLength', maxLength);
        elem.removeAttribute(ATTR_MAXLENGTH);
      }

      // If the polyfill has changed the type of the element we need to change
      // it back.
      var type = elem.getAttribute(ATTR_INPUT_TYPE);
      if ( type ) {
        elem.type = type;
      }

      return true;
    }

    return false;
  }

  // Show the placeholder value on a single element. Returns true if the
  // placeholder was shown and false if it was not (because it was already
  // visible).
  function showPlaceholder( elem ) {

    var val = elem.getAttribute(ATTR_CURRENT_VAL);

    if ( elem.value === '' && val ) {

      elem.setAttribute(ATTR_ACTIVE, 'true');
      elem.value = val;
      elem.className += ' ' + placeholderClassName;

      // Store and remove the maxlength value.
      var maxLength = elem.getAttribute(ATTR_MAXLENGTH);
      if ( !maxLength ) {
        elem.setAttribute(ATTR_MAXLENGTH, elem.maxLength);
        elem.removeAttribute('maxLength');
      }

      // If the type of element needs to change, change it (e.g. password
      // inputs).
      var type = elem.getAttribute(ATTR_INPUT_TYPE);
      if ( type ) {
        elem.type = 'text';
      } else if ( elem.type === 'password' && changeType(elem, 'text') ) {
        elem.setAttribute(ATTR_INPUT_TYPE, 'password');
      }

      return true;
    }

    return false;
  }

  // Returns a function that is used as a focus event handler.
  function makeFocusHandler( elem ) {
    return function () {

      // Only hide the placeholder value if the (default) hide-on-focus
      // behaviour is enabled.
      if (
        hideOnInput &&
        elem.value === elem.getAttribute(ATTR_CURRENT_VAL) &&
        elem.getAttribute(ATTR_ACTIVE) === 'true'
      ) {

        // Move the caret to the start of the input (this mimics the behaviour
        // of all browsers that do not hide the placeholder on focus).
        moveCaret(elem, 0);
      } else {

        // Remove the placeholder.
        hidePlaceholder(elem);
      }
    };
  }

  // Returns a function that is used as a blur event handler.
  function makeBlurHandler( elem ) {
    return function () {
      showPlaceholder(elem);
    };
  }

  // Returns a function that is used as a submit event handler on form elements
  // that have children affected by this polyfill.
  function makeSubmitHandler( form ) {
    return function () {

        // Turn off placeholders on all appropriate descendant elements.
        disablePlaceholders(form);
    };
  }

  // Functions that are used as a event handlers when the hide-on-input
  // behaviour has been activated - very basic implementation of the 'input'
  // event.
  function makeKeydownHandler( elem ) {
    return function ( e ) {
      keydownVal = elem.value;

      // Prevent the use of the arrow keys (try to keep the cursor before the
      // placeholder).
      if (
        elem.getAttribute(ATTR_ACTIVE) === 'true' &&
        keydownVal === elem.getAttribute(ATTR_CURRENT_VAL) &&
        inArray(badKeys, e.keyCode)
      ) {
        if ( e.preventDefault ) {
            e.preventDefault();
        }
        return false;
      }
    };
  }

  function makeKeyupHandler(elem) {
    return function () {
      hidePlaceholder(elem, keydownVal);

      // If the element is now empty we need to show the placeholder
      if ( elem.value === '' ) {
        elem.blur();
        moveCaret(elem, 0);
      }
    };
  }

  function makeClickHandler(elem) {
    return function () {
      if (
        elem === safeActiveElement() &&
        elem.value === elem.getAttribute(ATTR_CURRENT_VAL) &&
        elem.getAttribute(ATTR_ACTIVE) === 'true'
      ) {
        moveCaret(elem, 0);
      }
    };
  }

  // Bind event handlers to an element that we need to affect with the
  // polyfill.
  function newElement( elem ) {

    // If the element is part of a form, make sure the placeholder string is
    // not submitted as a value.
    var form = elem.form;
    if ( form && typeof form === 'string' ) {

      // Get the real form.
      form = document.getElementById(form);

      // Set a flag on the form so we know it's been handled (forms can contain
      // multiple inputs).
      if ( !form.getAttribute(ATTR_FORM_HANDLED) ) {
        addEventListener(form, 'submit', makeSubmitHandler(form));
        form.setAttribute(ATTR_FORM_HANDLED, 'true');
      }
    }

    // Bind event handlers to the element so we can hide/show the placeholder
    // as appropriate.
    addEventListener(elem, 'focus', makeFocusHandler(elem));
    addEventListener(elem, 'blur', makeBlurHandler(elem));

    // If the placeholder should hide on input rather than on focus we need
    // additional event handlers
    if (hideOnInput) {
      addEventListener(elem, 'keydown', makeKeydownHandler(elem));
      addEventListener(elem, 'keyup', makeKeyupHandler(elem));
      addEventListener(elem, 'click', makeClickHandler(elem));
    }

    // Remember that we've bound event handlers to this element.
    elem.setAttribute(ATTR_EVENTS_BOUND, 'true');
    elem.setAttribute(ATTR_CURRENT_VAL, placeholder);

    // If the element doesn't have a value and is not focussed, set it to the
    // placeholder string.
    if ( hideOnInput || elem !== safeActiveElement() ) {
      showPlaceholder(elem);
    }
  }

}(this) );

/*! Respond.js v1.4.2: min/max-width media query polyfill
 * Copyright 2014 Scott Jehl
 * Licensed under MIT
 * http://j.mp/respondjs */

/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
(function(w) {
  "use strict";
  w.matchMedia = w.matchMedia || function(doc, undefined) {
    var docElem  = doc.documentElement,
        refNode  = docElem.firstElementChild || docElem.firstChild,
        // fakeBody required for <FF4 when executed in <head>
        fakeBody = doc.createElement('body'),
        div      = doc.createElement('div'),
        bool,
        fakeUsed;

    div.id = 'mq-test-1';
    div.style.cssText = "position:absolute;top:-100em";
    fakeBody.style.background = "none";
    fakeBody.appendChild(div);

    var mqRun = function ( mq ) {
      div.innerHTML = '&shy;<style media="' + mq + '"> #mq-test-1 { width: 42px; }</style>';
      docElem.insertBefore( fakeBody, refNode );
      bool = div.offsetWidth === 42;
      docElem.removeChild( fakeBody );
      
      return { matches: bool, media: mq };
    },
    
    getEmValue = function () {
      var ret,
          bodyState = getBody(),
          body = bodyState.body,
          fakeUsed = bodyState.isFake;

      div.style.cssText = "position:absolute;font-size:1em;width:1em";

      body.appendChild( div );

      docElem.insertBefore( body, docElem.firstChild );

      if( fakeUsed ) {
        docElem.removeChild( body );
      } else {
        body.removeChild( div );
      }
      
      //also update eminpx before returning
      ret = eminpx = parseFloat( div.offsetWidth );

      return ret;
    },

    getBody = function() {
      var body = docElem.body,
          isFake = false;

      if( !body ) {
        body = fakeUsed = doc.createElement( "body" );
        body.style.background = "none";
        isFake = true;
      }

      return {
        body: body,
        isFake: isFake
      };
    },
    
    //cached container for 1em value, populated the first time it's needed 
    eminpx,
    
    // verify that we have support for a simple media query
    mqSupport = mqRun( '(min-width: 0px)' ).matches;

    return function ( mq ) {
      if( mqSupport ) {
        return mqRun( mq );
      } else {
        var min = mq.match( /\(min\-width[\s]*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
            max = mq.match( /\(max\-width[\s]*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
            minnull = min === null,
            maxnull = max === null,
            currWidth = getBody().body.offsetWidth,
            em = 'em';
        
        if( !!min ) { min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); }
        if( !!max ) { max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); }
        
        bool = mqRun(mq).matches || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max );

        return { matches: bool, media: mq };
      }
    };
  }(w.document);
})(this);

/*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */
(function(w) {
  "use strict";
  if (w.matchMedia && w.matchMedia("all").addListener) {
    return false;
  }
  var localMatchMedia = w.matchMedia, hasMediaQueries = localMatchMedia("only all").matches, isListening = false, timeoutID = 0, queries = [], handleChange = function(evt) {
    w.clearTimeout(timeoutID);
    timeoutID = w.setTimeout(function() {
      for (var i = 0, il = queries.length; i < il; i++) {
        var mql = queries[i].mql, listeners = queries[i].listeners || [], matches = localMatchMedia(mql.media).matches;
        if (matches !== mql.matches) {
          mql.matches = matches;
          for (var j = 0, jl = listeners.length; j < jl; j++) {
            listeners[j].call(w, mql);
          }
        }
      }
    }, 30);
  };
  w.matchMedia = function(media) {
    var mql = localMatchMedia(media), listeners = [], index = 0;
    mql.addListener = function(listener) {
      if (!hasMediaQueries) {
        return;
      }
      if (!isListening) {
        isListening = true;
        w.addEventListener("resize", handleChange, true);
      }
      if (index === 0) {
        index = queries.push({
          mql: mql,
          listeners: listeners
        });
      }
      listeners.push(listener);
    };
    mql.removeListener = function(listener) {
      for (var i = 0, il = listeners.length; i < il; i++) {
        if (listeners[i] === listener) {
          listeners.splice(i, 1);
        }
      }
    };
    return mql;
  };
})(this);


//window.Promise = window.Promise || RSVP.Promise;

(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.MDP = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var ServiceLocator = require('./servicelocator'),
    ModuleMediator = require('./modulemediator'),

    APIServiceParser = require('./services/apiserviceparser'),
    ServiceRegistry = require('./services/serviceregistry'),
    TemplateService = require('./services/templateservice'),
    HelperService = require('./services/helperservice');

/**
 * @constructor
 * @param {HTMLElement|jQuery} context
 * @param {object} config
 */
function Application(context, config) {
  this.config = config ? config : {};

  var services = new ServiceRegistry(this);
  this.services = services.services;
  this.registerService = services.register.bind(services);

  var helpers = new HelperService(this);
  this.helpers = helpers.helpers;
  this.registerHelper = helpers.register.bind(helpers);

  this.registerService('templateService', TemplateService);

  this.modules = new ModuleMediator(this);
  this.registerModule = this.modules.registerModule.bind(this.modules);

  if (context) this.setContext(context);

  setupApiServices.call(this, this);
}

/**
 * @public
 * @param {HTMLElement|jQuery} context
 */
Application.prototype.setContext = function(context) {
  var ctx = !!context.jquery ? context.get(0) : context;
  this._DOMContext = ctx;
  this.modules.setContext(ctx);
};

function setupApiServices(app) {
  var apiServices = new ServiceLocator('apis');

  // XXX: Replace below with something sensible!
  app.registerAPI = function(s) {
    var serviceManifest = typeof s === 'object' ? s : {},
        services = APIServiceParser.parse(serviceManifest);

    services.forEach(function(api) {
      apiServices.register(api.name, api);
    });
  };
  this.registerService('apis', apiServices.apis);
}

/**
 * @export Application
 */
module.exports = Application;


},{"./modulemediator":6,"./servicelocator":9,"./services/apiserviceparser":11,"./services/helperservice":12,"./services/serviceregistry":15,"./services/templateservice":16}],2:[function(require,module,exports){
var constants,
    moduleObj = new ConstantMap;

function ConstantMap() {}

/**
 * @enum
 */
constants = {
  MODULE_ID_ATTR: 'data-module-type',
  MARKET_ID_ATTR: 'data-market-type',
  BINDING_ATTR: 'data-bind',
  BINDING_KEY_DELIMITER: ':'
};

for (var c in constants) {
  !function(cKey) {
    Object.defineProperty(moduleObj, cKey, {
      enumerable: true,
      value: constants[cKey]
    });
  }(c);
}

/**
 * @export ConstantMap
 */
module.exports = moduleObj;


},{}],3:[function(require,module,exports){
/**
 * @constructor
 * @param {Error} error
 * @param {object} module
 */
function ModuleError(error, module) {
  var sourcePosition, sourceExcerpt, errorOutput, errorMessage,
      sourceOffsetBegin, sourceOffsetEnd, lineNumberPadding,
      errorLine;

  if (error && traceableError(error)) {
    sourcePosition = error.stack
      .replace(/\n/g, '@@newline@@')
      .match(new RegExp('@@newline@@.*bootstrapModule'));
  }

  try {
    sourcePosition = error.stack.replace(/\n/g,'@@newline@@')
      .match(new RegExp('@@newline@@.*bootstrapModule'));
    sourcePosition = sourcePosition[0].split('@@newline@@');
    sourcePosition = sourcePosition.filter(function(l) {
      return l.indexOf('>:') !== -1
          || l.indexOf('sandbox.js:') !== -1;
    })[0];
    sourcePosition = sourcePosition.split(/[:\)]/).slice(-3, -1);
    sourcePosition = sourcePosition.reduce(function(a, b, i) {
      a[['x', 'y'][i]] = Math.max(parseInt(b) - 2, 1);
      return a;
    }, {});

    sourceOffsetBegin = Math.max(sourcePosition.x - 5, 0);
    sourceOffsetEnd = sourceOffsetBegin + 10;
    lineNumberPadding = sourceOffsetEnd.toString().length;

    sourceExcerpt = module.controller.toString().split('\n');
    sourceExcerpt = sourceExcerpt.slice(sourceOffsetBegin, sourceOffsetEnd);
    sourceExcerpt = sourceExcerpt.map(function(src, i) {
      var lineNumber = sourceOffsetBegin + i + 1,
          lineNumberLength = lineNumber.toString().length,
          lineDiff = lineNumberPadding - lineNumberLength;

      if (lineDiff !== 0) {
        lineNumber = Array(lineDiff + 1).join(' ') + lineNumber;
      }

      return lineNumber + ' | ' + src;
    });

    errorLine = sourcePosition.x - sourceOffsetBegin - 3;
    console.log(errorLine);
    sourceExcerpt[0] = '%c' + sourceExcerpt[0];
    sourceExcerpt[errorLine] = [
      '%c', sourceExcerpt[errorLine],
      '  <<  ', error.message + '%c'
    ].join('');
    sourceExcerpt[errorLine] = sourceExcerpt[errorLine];
    sourceExcerpt = sourceExcerpt.join('\n');

    errorOutput = [
      [sourceExcerpt].join(''),
      'font-weight:normal; color:darkgrey;',
      'font-weight:bold; color:darkred;',
      'font-weight:normal; color:darkgrey;'
    ];

    errorMessage = [
      '%cError in module: "%s" on line %d',
      'font-weight:bold; color:darkred;',
      module.type,
      (sourcePosition.x - 1)
    ];
    // !!! Finish nice clean error output
  } catch(e) {
    sourcePosition = { x: 0, y: 0 };
    errorMessage = [
      '%cError in module: "%s" (%s)',
      'font-weight:bold; color:darkred;',
      module.type,
      module.market
    ];
    errorOutput = [
      [
        '%cUnable to display source for this error,',
        'please see error object below'
      ].join(' '),
      'font-weight:normal; color:darkgrey;'
    ];
  }

  console.groupCollapsed.apply(console, errorMessage);
  console.log.apply(console, errorOutput);
  if (error.stack) {
    console.error(error.stack);
  } else {
    console.error('Partial trace for error: "' + JSON.stringify(error) + '"');
  }
  console.groupEnd();
}

function traceableError(error) {
  return error.stack
      && error.stack.replace;
}

/**
 * @export ModuleError
 */
module.exports = ModuleError;

},{}],4:[function(require,module,exports){
var Console = require('console.js');
if (typeof window.execScript !== 'undefined' ||
    typeof console.groupCollapsed === 'undefined') {
  Console.attach();
  Console.styles.attach();
}

/**
 * @namespace MDP
 */
var MDP = {};
/**
 * @property {Application} Application
 */
MDP.Application = require('./application');

/**
 * @property {View} View
 */
MDP.View = require('./view');

/**
 * @property {ViewModel} ViewModel
 */
MDP.ViewModel = require('./viewmodel');

/**
 * @property {Module} Module
 */
MDP.Module = require('./module');

/**
 * @namespace MDP.Services
 */
MDP.Services = {};

/**
 * @property {Service} Service
 */
MDP.Services.Service = require('./services/service');

/**
 * @namespace MDP.types
 */
MDP.types = {};

/**
 * @property {ObservableArray} ObservableArray
 */
MDP.types.ObservableArray = require('./utils/observablearray');

/*
 * @property {Computed} Computed
 */
//MDP.types.Computed = require('./utils/computed')



/**
 * @export MDP
 */
module.exports = MDP;


},{"./application":1,"./module":5,"./services/service":14,"./utils/observablearray":17,"./view":18,"./viewmodel":19,"console.js":23}],5:[function(require,module,exports){
var View = require('./view'),
    ServiceLocator = require('./servicelocator'),
    ServiceMap = ServiceLocator.ServiceMap;

function Module(services, view) {
  this.services = services instanceof ServiceMap ? services : null;

  this.view = null;
  if (view instanceof View) this.setRootView(view);
}

Module.prototype.setRootView = function setRootView(newView) {
  this.view = newView;
};

module.exports = Module;


},{"./servicelocator":9,"./view":18}],6:[function(require,module,exports){
var View = require('./view'),
    Module = require('./module'),
    ModuleError = require('./errors/moduleerror'),
    LocalTemplateService = require('./services/localtemplateservice'),
    idAttr = require('./constants').MODULE_ID_ATTR,
    marketAttr = require('./constants').MARKET_ID_ATTR,
    vm = require('vm'),
    VMContext = require('./vmcontext'),
    Sandbox = require('./sandbox'),
    ObservableArray = require('./utils/observablearray');

var nullifyObserver = function() {};

var DefaultConfig = {
  marketId: 'core'
};

/**
 * @constructor
 * @param {Application} application
 *    Application instance
 */
function ModuleMediator(application) {
  var mutationObserver;

  this['application '] = application;
  this._config = $.extend({}, DefaultConfig, application.config);

  this.isWatching = false;
  this._observer = null;
  this._modules = {};
  this.sandbox = null;
  
  if (this['application ']._DOMContext) {
    this.setContext(_appInstance._DOMContext);
  }
}

/**
 * @public
 * @param {HTMLElement|jQuery} context
 */
ModuleMediator.prototype.setContext = function(context) {
  var ctx = !!context.jquery ? context.get(0) : context;

  this._context = ctx;

  if (this.isWatching)
    this.stop();

  this.sandbox = new Sandbox(null, this._context);
  this.start();
};

/**
 * @public
 */
ModuleMediator.prototype.start = function() {
  var appInstance = this['application '],
      sandbox = this.sandbox,
      observer,
      moduleStream;

  if (this._context) {
    observer = Rx.Observer.create(function(module) {
        var instance = bootstrapModule(module, appInstance, sandbox);
        console.info('Bound module: %o', module, instance);
      });

    moduleStream = watchModules(this._context, this._modules, this);

    Rx.Observable.catchException(moduleStream).subscribe(observer);

    //moduleStream.subscribe(observer);
  }

  this._observer = observer;
  this.isWatching = true;
};

/**
 * @public
 */
ModuleMediator.prototype.stop = function() {
  if (!this.isWatching) return;

  nullifyObserver = function() {
    this._observer = null;
  };

  this.isWatching = false;
  this._observer.dispose();
};

/**
 * @public
 * @param {string} name
 * @param {string} market
 * @param {function} module
 */
ModuleMediator.prototype.registerModule = function(name, market, module) {
  var args = [].slice.apply(arguments);

  if (typeof market !== 'string' || args.length === 2) {
    module = market;
    market = this._config.marketId || 'core';
  }

  if (!!this._modules[name] && !!this._modules[name][market]) {
    return console.error([
      'Module with name: "',
      name,
      '" has already been registered for market: "',
      market,
      '"'
    ].join(''));
  }

  this._modules[name] = this._modules[name] || {};
  this._modules[name][market] = module;
  console.groupCollapsed('Registered module: "%s" (%s)', name, market);
  console.log(module);
  console.groupEnd();
};

/**
 * @private
 * @param {HTMLElement} context
 * @param {object} modules
 * @param {ModuleMediator} mediator
 * @return {Rx.Observable}
 */
function watchModules(context, modules, mediator) {
  var target = context,
      registeredModules = modules,
      marketId = mediator._config.marketId,
      prerendered = target.querySelectorAll('[' + idAttr + ']'),
      prerenderedObservable = Rx.Observable.fromArray(prerendered),
      mutationObservable = fromMutationObserver(target),
      modulesObservable;

  modulesObservable = mutationObservable.merge(prerenderedObservable);

  mediator._observer = modulesObservable;

  return moduleResults(modulesObservable, registeredModules, marketId);
}

/**
 * @private
 * @param {Array} modules
 * @param {object} registeredModules
 * @param {string} defaultMarket
 * @return {Rx.Observable}
 */
function moduleResults(modules, registeredModules, defaultMarket) {
  return modules
    .map(function(element) {
      var type = $(element).attr(idAttr),
          market = $(element).attr(marketAttr) || defaultMarket;

      return {
        element: element,
        type: type,
        market: market
      };
    })
    .filter(function(scope) {
      return !!scope.type &&
        !!scope.market &&
        !!registeredModules[scope.type] &&
        !!registeredModules[scope.type][scope.market];
    })
    .map(function(scope) {
      var isCore = scope.market === 'core';

      scope.controller = registeredModules[scope.type][scope.market];
      scope.controllerBase = isCore ?
        null :
        registeredModules[scope.type]['core'];

      return scope;
    })
    .filter(function(scope) {
      var isNew = true;

      if (!scope.type ||
         !scope.controller ||
         !!scope.element.module) return false;

      return true;
    });
}

/**
 * @private
 * @param {function} module
 * @param {Application} app
 * @param {Sandbox} sandbox
 */
function bootstrapModule(module, app, sandbox) {
  var controller = module.controller,
      controllerSrc = controller.toString()
          .replace(/function.*\{/, '')
          .slice(0, -1),
      isClass = (controller.prototype &&
          controller instanceof Module),
      view = new View(module.element),
      localTemplates = new LocalTemplateService(
        app.services('templateService'),
        module.type
      ),
      vmJquery, instance,
      context, contextInstance,
      controllerDefinition,
      asyncFn;

  contextInstance = new VMContext(module, view, app, localTemplates);
  contextInstance.context = context;
  contextInstance.contextInstance = contextInstance;

  asyncFn = function(op) {
    return function() {
      var args = [].slice.call(arguments),
          timerId, fn;

      fn = args[0];
      args[0] = function() {
        try {
          fn.apply(module.element.module, arguments);
        } catch (e) {
          ModuleError(e, module);
        }
      };
      try {
        return window[op].apply(null, args);
      } catch (e) {
        return window[op].apply(window, args);
      }
    }.bind(context);
  };

  contextInstance.MDP = contextInstance.MDP || MDP;
  contextInstance.Math = contextInstance.Math || Math;

  contextInstance.base = null;
  context = VMContext.objectify(contextInstance);
  context.context = context;

  if (module.controllerBase) {
    contextInstance.base = context.base = sandboxClass(
      sandbox,
      module.controllerBase,
      context,
      [module.type, 'core'].join('_')
    );
  }

  controllerDefinition = sandboxClass(
    sandbox,
    controller,
    context,
    [module.type, module.market].join('_')
  );

  if (controllerDefinition) {
    try {
      instance = new controllerDefinition(context);
      module.element.module = instance;
      module.element.classDef = controllerDefinition;
    } catch (e) {
      ModuleError(e, module);
    }
  }

  return instance;
}

function sandboxClass(sandbox, controller, context, name) {
  var result,
      moduleName = typeof name === 'string' && name ||
        (+(new Date()) + '_sandbox');

  try {
    result = sandbox.evaluate(controller, context, moduleName);
  } catch (e) {
    ModuleError(e, module);
  }

  return result;
}

/**
 * @private
 * @param {string} controller
 * @return {string}
 */
function wrapModule(controller) {
  var output = [],
      isLegacy = isFragileJSVM();

  output.push('(function(context, window) {');
  if (!isLegacy) output.push('"use strict";');
  if (isLegacy) output.push('with (context) {');
  output.push('return (' + controller + ').apply(context)');
  if (isLegacy) output.push('}');
  output.push('}).apply(context)');

  return output.join('\n');
}

function isFragileJSVM() {
  return !!navigator.userAgent.toString().match(/(msie|trident)/i);
}

/**
 * @private
 * @param {HTMLElement} target
 * @return {Rx.Observable}
 */
function fromMutationObserver(target) {
  var scheduler = isFragileJSVM() ?
        Rx.Scheduler.currentThread :
        Rx.Scheduler.timeout,
    observer = Rx.Observable.create(function(observer) {
    var mutationObserver = new MutationObserver(function(mutations) {
      Rx.Observable.fromArray(mutations)
        .map(function(mutation) {
          return mutation.addedNodes || [];
        })
        .concatMap(function(mutation) {
          return Rx.Observable.fromArray(mutation);
        })
        .forEach(function(element) {
          observer.onNext(element);
        });
    });

    mutationObserver.observe(target, {
      childList: true,
      subtree: true
    });

    return function() {
      mutationObserver.disconnect();
      nullifyObserver();
    };
  })
  .observeOn(scheduler);

  return observer;
}

/**
 * @export ModuleMediator
 */
module.exports = ModuleMediator;


},{"./constants":2,"./errors/moduleerror":3,"./module":5,"./sandbox":8,"./services/localtemplateservice":13,"./utils/observablearray":17,"./view":18,"./vmcontext":20,"vm":21}],7:[function(require,module,exports){
/**
 * @constructor
 */
function RequestDispatcher() {
  this._requestQueue = [];
}

/**
 * @public
 * @param {RequestOperation} operation
 */
RequestDispatcher.prototype.queue = function(operation) {

};

/**
 * @export RequestDispatcher
 */
module.exports = RequestDispatcher;


},{}],8:[function(require,module,exports){
var jsGlobals, ContextStore;

/**
 * @constructor
 * @param {Object} baseContext
 * @param {HTMLElement} parentElement
 */
function Sandbox(baseContext, parentElement) {
  var parent = !!parentElement ? parentElement : document.body,
      iframe = createIframe(),
      sandboxContext = !!baseContext ? baseContext : {},
      contextFrame, contextWindow;

  parent.appendChild(iframe);
  //try { iframe.contentDocument.domain = document.domain; } catch (e) { }

  contextFrame = iframe;
  contextWindow = iframe.contentWindow;

  this.getContextFrame = function() { return contextFrame; };
  this.getContextWindow = function() { return contextWindow; };
  this._destroyContextFrameReference = function() { contextFrame = null; };

  Object.keys(sandboxContext)
    .forEach(function(k) { contextWindow[k] = sandboxContext[k]; });

  if (!supportsES5StrictMode()) {
    contextWindow.execScript('null');

    'Array,Object,Function,Date,Number'.split(',')
      .forEach(function(v) {
        Object.keys(window[v]).forEach(function(m) {
          contextWindow.eval(v)[m] = window[v][m];
        });

        Object.keys(window[v].prototype).forEach(function(m) {
          contextWindow.eval(v).prototype[m] = window[v].prototype[m];
        });
      });

    contextWindow.eval('Object').defineProperty = Object.defineProperty;
  }
}

/**
 * @public
 * @param {Function|String} code
 * @param {Object} executionContext
 * @return {*}
 */
Sandbox.prototype.evaluate = function(code, executionContext, name) {
  var win = this.getContextWindow(),
      exec = supportsES5StrictMode() ? execES5 : execLegacy,
      result, restoreEnvironment;

  result = exec(code, win, executionContext, name);

  return result;
};

/**
 * @public
 */
Sandbox.prototype.destroy = function() {
  var iframe = this.getContextFrame();
  if (iframe) {
    iframe.parentNode.removeChild(iframe);
    this._destroyContextFrameReference();
  }
};

function prepareEnvironment(env, context) {
  var win = env,
      defaultContextVars = {};

  Object.keys(context)
    .forEach(function(k) {
      defaultContextVars[k] = win[k];
      win[k] = context[k];
    });

  return function() {
    Object.keys(defaultContextVars)
      .forEach(function(k) {
        win[k] = defaultContextVars[k];
      });
  }
}

function execES5(code, win, context, name) {
  var finalSource,
      functionArgs,
      argumentValues,
      resetStatement = '';

  finalSource = [
    '"use strict";',
    resetStatement,
    'return (' + code + '.apply(null))',
    '\n//# sourceURL=' + name + '\n'
  ].join('\n');

  functionArgs = Object.keys(context);
  argumentValues = functionArgs.map(function(k) { return context[k]; });
  functionArgs.push(finalSource);

  return (win.Function
    .apply(null, functionArgs)
    .apply(context, argumentValues));
}

function execLegacy(code, win, context) {
  var contextId = injectContext(win, context),
      src = [
        '(function(context) {',
          'with (context) {',
            'return (' + code + '.apply(context));',
          '}',
        '}.apply(context, [context(' + contextId + ')]));'
      ].join('\n');

  win.execScript('null');

  return win.eval(src);
}

function createIframe() {
  var iframe = document.createElement('iframe');
  iframe.style.display = 'none';
  iframe.src = 'about:blank';
  return iframe;
}

function supportsES5StrictMode() {
  'use strict'; // _should_ prevent global access via `this`
  function test() { return function() { return eval('this'); }.call(this); }
  return (test.call(null) === null);
}

function injectContext(win, context) {
  if (typeof win.context === 'undefined') {
    win.context = new ContextStore();
  }

  return win.context(context);
}

ContextStore = (function() {

  function ContextStore() {
    var pending = {},
        allocated = [];

    function get(v) {
      var allocatedIndex = allocated.indexOf(v),
          value;

      if (allocatedIndex >= 0) {
        value = pending[v]

        delete pending[v];
        allocated.splice(allocatedIndex, 1);

        return value;
      } else {
        return null
      }
    }

    function store(v) {
      var isUnique = false,
          contextId;

      while(!isUnique) {
        contextId = parseInt(Math.random() * (1 << 30));
        isUnique = allocated.indexOf(contextId) === -1;
      }

      allocated.push(contextId);
      pending[contextId] = v;

      return contextId;
    }

    return function(v) {
      return (typeof v === 'number') ? get(v) : store(v);
    }
  }

  return ContextStore;

}.apply(null));

jsGlobals = (function() {
  var names = [
        'Array', 'ArrayBuffer', 'Boolean', 'Collator', 'DataView', 'Date',
        'DateTimeFormat', 'decodeURI', 'decodeURIComponent', 'encodeURI',
        'encodeURIComponent', 'Error', 'eval', 'EvalError', 'Float32Array',
        'Float64Array', 'Function', 'Infinity', 'Intl', 'Int16Array', 
        'Int32Array', 'Int8Array', 'isFinite', 'isNaN', 'Iterator', 'JSON',
        'Math', 'NaN', 'Number', 'NumberFormat', 'Object', 'parseFloat', 
        'parseInt', 'RangeError', 'ReferenceError', 'RegExp', 'StopIteration',
        'String', 'SyntaxError', 'TypeError', 'Uint16Array', 'Uint32Array',
        'Uint8Array', 'Uint8ClampedArray', 'undefined', 'uneval', 'URIError'
      ],
      jsGlobals = Object.create(null);

  names
    .filter(function(k) { return k in this; })
    .forEach(function(k) { jsGlobals[k] = void 0; });

  return jsGlobals;
}.apply(null));

/**
 * @export Sandbox
 */
module.exports = Sandbox;

},{}],9:[function(require,module,exports){
function safeLog() {
  var args = [].slice.apply(arguments);
  try {
    console.error.apply(console, args);
  } catch(e) {
    console.log.apply(console, args);
  }
}

function ServiceLocator(name)
{
  var ServiceLocator,
      _services = new ServiceMap(),
      directoryName = name || 'services';

  /**
   * @constructor
   * @param {string} name
   */
  function ServiceLocator() {
    /**
     * @public
     * @param {string} name
     */
    this[directoryName] = function(name) {
      if (name == null) return _services;
      return _services[name] || null;
    }
  }

  /**
   * @public
   * @param {string} name
   * @param {function} service
   * @return {void}
   */
  ServiceLocator.prototype.register = function(name, service) {
    if (!!_services[name]) {
      return safeLog(name + ' has already been registered.');
    }

    _services[name] = service;

    //Object.defineProperty(_services, name, {
      //enumerable: true,
      //configurable: false,
      //value: service
    //});
  };

//ServiceLocator.prototype.remove = function(name) {
  //try {
    //delete this.services[name];
  //} catch(e) {}
//};

  return new ServiceLocator();
}

function ServiceMap() {}

ServiceLocator.ServiceMap = ServiceMap;

/**
 * @export ServiceLocator
 */
module.exports = ServiceLocator;


},{}],10:[function(require,module,exports){
var Service = require('./service'),
    RequestDispatcher = require('../network/requestdispatcher'),
    TaffyDB = require('taffydb').taffy,
    verbMap = {
      'POST' : 'create',
      'PUT' : 'update',
      'DELETE' : 'delete'
    },
    verbFunctionMap;


function APIService(url, manifest, dispatcher) {
  var apiName = manifest.name || url.replace(/\//g, '');

  if (!url && !url.length) {
    throw new error('APIService constructor invoked without \'url\' argument.');
  }

  if (!(dispatcher && dispatcher.length)) {
    console.info([
      'APIService constructor invoked',
      'without \'dispatcher\' argument.',
      'Using new RequestDispatcher instead,',
      'requests will not be pipelined'
    ].join(' '));
  }

  this.store = TaffyDB();
  this.dispatcher = dispatcher || new RequestDispatcher;

  Service.apply(this);

  this.name = apiName;
  manifest = manifest || {
    name: apiName,
    query: ['id'],
    actions: ['GET']
  };

  createMethods.call(this, manifest);
}

function createMethods(options) {
  Object.keys(verbMap)
    .filter(function(verb) { return options.actions.indexOf(verb) !== -1; })
    .forEach(function(verb) { createMethod.call(this, verb); }.bind(this));

  createGetMethods.call(this, options.query);
}

function createMethod(verb) {
  var method = verbMap[verb];
  //debugger
  this[method] = verbFunctionMap[method];
}

function createGetMethods(queryables) {
  queryables.forEach(function(q) {
    var suffix = q[0].toUpperCase() + q.slice(1),
        method = 'getBy' + suffix;

    this[method] = function(param) {
      var field = q;
      verbFunctionMap;
    };
  }.bind(this));
}

verbFunctionMap = {
  'get': function(query) {
    var cachedData = this.store(query).get();
  },
  'create': function(doc) {
    this.store.insert(doc);
  },
  'update': function(doc) {
    var operation = {
      operation: 'put',
      query: {
        id: id
      }
    };

    this.store({
      id: doc.id
    }).update(doc);

    this.dispatcher.queue(this.endpoint, operation);
  },
  'delete' : function(id) {
    var operation = {
      operation: 'delete',
      query: {
        id: id
      }
    };

    this.store({ id: id }).remove();
    this.dispatcher.queue(this.endpoint, operation);
  }
};

APIService.prototype = new Service();

/**
 * @export APIService
 */
module.exports = APIService;


},{"../network/requestdispatcher":7,"./service":14,"taffydb":24}],11:[function(require,module,exports){
var APIService = require('./apiservice'),
    urljoin = require('url-join'),

    httpVerbs = ['GET', 'POST', 'PUT', 'DELETE'];

function APIServiceParser(serviceDescription, options) {
  options = options || {
    baseUrl: urljoin(window.location.origin, '/api')
  };

  this.baseUrl = options.baseUrl;

  this.parsed = {};
  this.output = {};

  if (serviceDescription instanceof Array) {
    this.output = [];
    serviceDescription.forEach(function(service) {
      this.output.push(this.parseService(service));
    }.bind(this));
  } else {
    this.output = [this.parseService(serviceDescription)];
  }
}

APIServiceParser.prototype.parseService = function(service) {
  var isExternal = !!service.external,
      serviceUrl,
      serviceInstance,
      serviceName;

  if (!validateService(service)) {
    return console.error([
      'Could not validate service: "',
      service,
      '" due to invalid descriptor'
    ].join(''));
  }

  serviceUrl = isExternal ? service.url : this.baseUrl + '/' + service.url;
  serviceUrl = serviceUrl.replace(/\/\/+/, '/');

  serviceName = service.name || service.url.replace(/\//g, '');

  serviceInstance = new APIService(serviceUrl, {
    name: serviceName,
    actions: service.actions,
    query: service.queryable
  });

  return serviceInstance;
};

function validateService(service) {
  var validUrl, validActions, comparisonActions;

  validUrl = service.url &&
    typeof service.url === 'string' &&
    service.url.length > 0;

  comparisonActions = service.actions
    .filter(function(action) { return typeof action === 'string'; })
    .filter(function(action) { return httpVerbs.indexOf(action) >= 0; });

  validActions = service.actions &&
    service.actions instanceof Array &&
    service.actions.length === comparisonActions.length;

  return validUrl && validActions;
}

function parse(serviceDescription, options) {
  var parser = new APIServiceParser(serviceDescription, options);
  return parser.output;
}

exports = module.exports = {
  parse: parse
};


},{"./apiservice":10,"url-join":25}],12:[function(require,module,exports){
var ServiceLocator = require('../servicelocator'),
    MAP_NAME = 'helpers';

/**
 * @constructor
 * @param {Application} application
 */
function HelperService(application) {
  this.application = application;

  ServiceLocator.call(this, MAP_NAME);
}

/**
 * @extends {ServiceLocator}
 */
HelperService.prototype = new ServiceLocator(MAP_NAME);

/**
 * @public
 * @param {string} name
 * @param {function} service
 * @return {void}
 */
HelperService.prototype.register = function(name, service) {
  var serviceDefinition;

  serviceDefinition = service(this.application);

  this.constructor.prototype.register.call(this, name, serviceDefinition);
};

/**
 * @export {HelperService}
 */
module.exports = HelperService;


},{"../servicelocator":9}],13:[function(require,module,exports){
/**
 * @constructor
 * @param {TemplateService} templateService
 * @param {String} moduleName
 */
function LocalTemplateService(templateService, moduleName) {
  var templates, globalService;
  
  this.moduleName = moduleName;
  globalService = this.globalService = templateService;
  templates = this.templates = {};

  Object.keys(this.globalService.templates())
    .map(function(name) {
      var tokens = name.split('.');
      return {
        module: tokens.shift(),
        ns: tokens.join('.'),
        name: name
      };
    })
    .filter(function(template) { return template.module === moduleName; })
    .forEach(function(template) {
      templates[template.ns] = globalService.templates(template.name);
    });
}

/**
 * @public
 * @param {string} name
 * @param {function} template
 */
LocalTemplateService.prototype.register = function(name, template) {
  var namespace = templateNamespace(this.moduleName, name),
      globalTemplates = this.globalService.templates;

  this.globalService.register(namespace, template);

  this.templates[name] = template;
};

/**
 * @private
 * @param {string} module
 * @param {string} name
 * @return {string}
 */
function templateNamespace(module, name) {
  var ns = [module, name].join('.');
  return ns;
}

/**
 * @export {LocalTemplateService}
 */
module.exports = LocalTemplateService;


},{}],14:[function(require,module,exports){
/**
 * @constructor
 */
function Service() {

}

/**
 * @export {Service}
 */
module.exports = Service;


},{}],15:[function(require,module,exports){
var ServiceLocator = require('../servicelocator');

var MAP_NAME = 'services';

function ServiceRegistry(application) {
  var application;

  /**
   * @constructor
   * @param {Application} application
   */
  function ServiceRegistry(application) {
    this.application = application;
    ServiceLocator.call(this, MAP_NAME);
  }

  /**
   * @extends {ServiceLocator}
   */
  ServiceRegistry.prototype = new ServiceLocator(MAP_NAME);

  /**
   * @public
   * @param {string} name
   * @param {function} service
   */
  ServiceRegistry.prototype.register = function(name, service) {
    var serviceInstance = service;

    while (typeof serviceInstance === 'function') {
      serviceInstance = new serviceInstance(this.application);
    }

    this.constructor.prototype.register.call(this, name, serviceInstance);
  };

  return new ServiceRegistry(application);
}

/**
 * @export {ServiceRegistry}
 */
module.exports = ServiceRegistry;


},{"../servicelocator":9}],16:[function(require,module,exports){
var ServiceLocator = require('../servicelocator');

var MAP_NAME = 'templates';

/**
 * @constructor
 */
function TemplateService() {
  ServiceLocator.call(this, MAP_NAME);
}

/**
 * @extends {ServiceLocator}
 */
TemplateService.prototype = new ServiceLocator(MAP_NAME);

/**
 * @param {string} name
 * @param {function} service
 * /
TemplateService.prototype.register = function(name, service) {
  var namespace = name.split('.'),
      rootNs = namespace.shift(),
      templateNamespace = this[MAP_NAME][rootNs];

  if (!templateNamespace) {
    templateNamespace = (!namespace.length) ? service : {};
    this.constructor.prototype.register.call(this,
                                           rootNs,
                                           templateNamespace);
  }

  namespace.reduce(function(currentNs, ns, nsIndex) {
    currentNs[ns] = currentNs[ns] ||
      nsIndex !== namespace.length - 1 ? {} : service;

    return currentNs[ns];
  }, templateNamespace);
};

/**
 * @export {TemplateService}
 */
module.exports = TemplateService;


},{"../servicelocator":9}],17:[function(require,module,exports){
var splice = Array.prototype.splice,
    noopFn = function() {};

/**
 * @constructor
 * @param {Array} items
 */
function ObservableArray(items) {
  this.values = [];
  this.lifetimes = [];

  for (item in items) {
    this.push(item);
  }

  Rx.Subject.call(this);
}

ObservableArray.prototype = new Rx.Subject;

/**
 * @public
 * @param {*} value
 * @return {number}
 */
ObservableArray.prototype.push = function(value) {
  var lifetime = new Rx.BehaviorSubject(value);

  this.values.push(value);
  this.lifetimes.push(lifetime);
  this.onNext(lifetime);

  return this.values.length;
};

/**
 * @public
 * @param {(function|Rx.Observer)=} obsOrNext
 * @return {Rx.Observable}
 */
ObservableArray.prototype.subscribe = function(obsOrNext) {
  var obsOrNext = obsOrNext || noopFn,
      subscription =
        Rx.BehaviorSubject.prototype.subscribe.apply(this, arguments),
      observerFn;

  this.purge();

  observerFn = typeof obsOrNext === 'function' ?
      obsOrNext :
      obsOrNext.onNext;

  for (var lifetime in lifetimes) {
    observerFn(lifetime);
  }

  return subscription;
};

/**
 * @public
 * @return {*}
 */
ObservableArray.prototype.pop = function() {
  var value = this.values.pop(),
      removed = this.lifetimes.pop();

  removed.onCompleted();

  return value;
};

/**
 * @public
 */
ObservableArray.prototype.splice = function() {
  var args = Array.prototype.slice.apply(arguments),
      removed;

  splice.apply(this.values, args);
  removed = splice.apply(this.lifetimes, args);

  for (var lifetime in removed) {
    lifetime.onCompleted();
  }
};

/**
 * @export ObservableArray
 */
module.exports = ObservableArray;


},{}],18:[function(require,module,exports){
var ViewModel = require('./viewmodel'),
    Constants = require('./constants');
//var tko = require("./bindings");

/**
 * @constructor
 * @param {HTMLElement|jQuery} element
 * @param {(ViewModel|object)=} viewModel
 */
function View(element, viewModel) {
  var vm;

  if (!element) throw new Error('Element must be provided to view');

  if (typeof viewModel !== "undefined") {
    if (viewModel instanceof ViewModel) {
      this.setViewModel(viewModel);
    }
  //} else {
    //this.setViewModel(decodeViewModel(element));
  }

  this._subViews = {};

  this.$ = $(element);
  this.element = this.$[0];
}

/**
 * @param {ViewModel} viewModel
 */
View.prototype.setViewModel = function(viewModel) {
  if (!(viewModel instanceof ViewModel))
    throw new Error("Argument 'viewModel' must be an instance of ViewModel");

  this._viewModel = viewModel;
};

/**
 * @private
 * @param {HTMLElement/jQuery} targetView
 * @return {ViewModel}
 * @deprecated Possibly no longer needed
 */
function decodeViewModel(targetView) {
  var bindTargets = $('[' + Constants.BINDING_ATTR + ']', targetView),
      vmKeys = [],
      vmData = {};

  bindTargets.each(function(i, el) {
    var binding = $(el).attr(Constants.BINDING_ATTR),
        bindingType, bindingKey, bindingOps;

    if (!binding) return true;

    bindingType = binding.split(Constants.BINDING_KEY_DELIMITER)[0];
    bindingKey = binding.split(Constants.BINDING_KEY_DELIMITER)[1];
    if (!bindingType || !bindingKey) return true;

    if (vmKeys.indexOf(bindingKey) < 0) vmKeys.push(bindingKey);

    vmData[bindingKey] = el.value || el.textContent;
  });

  return new ViewModel(vmData);
}

/**
 * @export ViewModel
 */
module.exports = View;


},{"./constants":2,"./viewmodel":19}],19:[function(require,module,exports){
var ObservableArray = require('./utils/observablearray');

/**
 * @constructor
 * @param {object} data
 * @param {ViewModel} root
 * @param {ViewModel} parent
 */
function ViewModel(data, root, parent) {
  this.$data = {};
  this.$root = root instanceof ViewModel && root || this;
  this.$parent = parent || null;

  if (!!data &&
      typeof data === 'object' &&
      !data.prototype) {
    this.$data = fromObject(data);
  }

  //debugger;
}

/**
 * @public
 * @param {string} name
 * @param {string|number|object} value
 */
ViewModel.prototype.set = function(name, value) {

};

/**
 * @public
 * @param {string} name
 */
ViewModel.prototype.get = function(name) {

};

/**
 * @public
 * @param {string} name
 */
ViewModel.prototype.value = function(name) {

};

/**
 * @private
 * @param {object} objData
 * @return {object}
 */
function fromObject(objData) {
  var vmData = {};

  for (var oKey in objData) {
    var oValue = objData[oKey];

    vmData[oKey] = valueToObservable(oValue);
  }

  return vmData;
}

/**
 * @private
 * @param {*} value
 * @return {Rx.Observable}
 */
function valueToObservable(value) {
  switch (typeof value) {
    case 'function':
      return value;

    case 'object':
      if (value instanceof Rx.Observable)
        return value;

      if (Array.isArray(value))
        return new ObservableArray(value);

    case 'undefined':
    case 'number':
    case 'string':
      return new Rx.BehaviorSubject(value);
  }
}

/**
 * @export ViewModel
 */
module.exports = ViewModel;


},{"./utils/observablearray":17}],20:[function(require,module,exports){
/**
 * @constructor
 */
function VMContext(module, view, app, localTemplates) {
  var vmJquery;

  /**
   * @public
   * @type {View}
   * @description
   */
  this.view = view;

  /**
   * @public
   * @type {ServiceRegistry}
   * @description
   */
  this.Services = app.services;

  /**
   * @public
   * @type {HelperService}
   * @description
   */
  this.Helpers = app.helpers;

  if (localTemplates) {
    /**
     * @public
     * @type {LocalTemplateService}
     */
    this.Templates = localTemplates.templates;
    this.registerTemplate = localTemplates.register.bind(localTemplates);
  }

  /**
   * @public
   * @type {EventBus}
   */
  this.Events = { todo: 'this' };

  /**
   * @private
   * @param {string|jQuery|HTMLElement} s
   * @return {jQuery}
   */
  vmJquery = function(s) {
    return $.call(null, s, view.$);
  };
  for (var field in $) {
    vmJquery[field] = $[field];
  }

  /**
   * @public
   * @type {jQuery}
   */
  this.jQuery = vmJquery;

  /**
   * @public
   * @type {jQuery}
   */
  this.$ = vmJquery;

  /**
   * @public
   * @type {function}
   */
  this.requestAnimationFrame = typeof requestAnimationFrame !== 'undefined' ?
    requestAnimationFrame :
    null;

  /**
   * @public
   * @type {function}
   */
  this.cancelAnimationFrame = typeof cancelAnimationFrame !== 'undefined' ?
    cancelAnimationFrame :
    null;

  /**
   * @public
   * @type {object}
   */
  this.ApplicationConfig = app.config;

  /**
   * @public
   * @type {object}
   */
  this.Config = null;
  if (app.config.modules && app.config.modules[module.type]) {
    this.Config = app.config.modules[module.type];
  }
}

/**
 * @public
 * @param {VMContext} context
 * @return {object}
 *
 * Transforms a VMContext instance into a plain JS object
 */
VMContext.objectify = function(context) {
  var output = {};
  for (var m in context) output[m] = context[m];
  return output;
};

window.console = window.console || [
    'log', 'info', 'error', 'warn', 'trace'
  ].reduce(function(a, b) {
    a[b] = new Function('console[b](arguments);');
  }, {});

VMContext.prototype = {
  window: null,
  Math: Math,
  Promise: Promise || RSVP.Promise,
  alert: function() { window.alert.apply(window, arguments); },
  Rx: Rx,
  __commandLineAPI: (typeof __commandLineAPI !== 'undefined' &&
      __commandLineAPI || {}),
  $debugger: new Function('debugger;'),
  $traceurRuntime: (typeof $traceurRuntime !== 'undefined' &&
    $traceurRuntime || {}),
  $__Object$defineProperty: Object.defineProperty,
  $__Object$defineProperties: Object.defineProperties,
  console: window.console
};

/**
 * @export VMContext
 */
module.exports = VMContext;

},{}],21:[function(require,module,exports){
var indexOf = require('indexof');

var Object_keys = function (obj) {
    if (Object.keys) return Object.keys(obj)
    else {
        var res = [];
        for (var key in obj) res.push(key)
        return res;
    }
};

var forEach = function (xs, fn) {
    if (xs.forEach) return xs.forEach(fn)
    else for (var i = 0; i < xs.length; i++) {
        fn(xs[i], i, xs);
    }
};

var defineProp = (function() {
    try {
        Object.defineProperty({}, '_', {});
        return function(obj, name, value) {
            Object.defineProperty(obj, name, {
                writable: true,
                enumerable: false,
                configurable: true,
                value: value
            })
        };
    } catch(e) {
        return function(obj, name, value) {
            obj[name] = value;
        };
    }
}());

var globals = ['Array', 'Boolean', 'Date', 'Error', 'EvalError', 'Function',
'Infinity', 'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError',
'ReferenceError', 'RegExp', 'String', 'SyntaxError', 'TypeError', 'URIError',
'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'escape',
'eval', 'isFinite', 'isNaN', 'parseFloat', 'parseInt', 'undefined', 'unescape'];

function Context() {}
Context.prototype = {};

var Script = exports.Script = function NodeScript (code) {
    if (!(this instanceof Script)) return new Script(code);
    this.code = code;
};

Script.prototype.runInContext = function (context) {
    if (!(context instanceof Context)) {
        throw new TypeError("needs a 'context' argument.");
    }
    
    var iframe = document.createElement('iframe');
    if (!iframe.style) iframe.style = {};
    iframe.style.display = 'none';
    
    document.body.appendChild(iframe);
    
    var win = iframe.contentWindow;
    var wEval = win.eval, wExecScript = win.execScript;

    if (!wEval && wExecScript) {
        // win.eval() magically appears when this is called in IE:
        wExecScript.call(win, 'null');
        wEval = win.eval;
    }
    
    forEach(Object_keys(context), function (key) {
        win[key] = context[key];
    });
    forEach(globals, function (key) {
        if (context[key]) {
            win[key] = context[key];
        }
    });
    
    var winKeys = Object_keys(win);

    var res = wEval.call(win, this.code);
    
    forEach(Object_keys(win), function (key) {
        // Avoid copying circular objects like `top` and `window` by only
        // updating existing context properties or new properties in the `win`
        // that was only introduced after the eval.
        if (key in context || indexOf(winKeys, key) === -1) {
            context[key] = win[key];
        }
    });

    forEach(globals, function (key) {
        if (!(key in context)) {
            defineProp(context, key, win[key]);
        }
    });
    
    document.body.removeChild(iframe);
    
    return res;
};

Script.prototype.runInThisContext = function () {
    return eval(this.code); // maybe...
};

Script.prototype.runInNewContext = function (context) {
    var ctx = Script.createContext(context);
    var res = this.runInContext(ctx);

    forEach(Object_keys(ctx), function (key) {
        context[key] = ctx[key];
    });

    return res;
};

forEach(Object_keys(Script.prototype), function (name) {
    exports[name] = Script[name] = function (code) {
        var s = Script(code);
        return s[name].apply(s, [].slice.call(arguments, 1));
    };
});

exports.createScript = function (code) {
    return exports.Script(code);
};

exports.createContext = Script.createContext = function (context) {
    var copy = new Context();
    if(typeof context === 'object') {
        forEach(Object_keys(context), function (key) {
            copy[key] = context[key];
        });
    }
    return copy;
};

},{"indexof":22}],22:[function(require,module,exports){

var indexOf = [].indexOf;

module.exports = function(arr, obj){
  if (indexOf) return arr.indexOf(obj);
  for (var i = 0; i < arr.length; ++i) {
    if (arr[i] === obj) return i;
  }
  return -1;
};
},{}],23:[function(require,module,exports){
if (!Array.prototype.forEach)
{
	Array.prototype.forEach = function(fun /*, thisArg */)
	{
		'use strict';

		if (this === void 0 || this === null) {
			throw new TypeError();
		}

		var t = Object(this);
		var len = t.length >>> 0;
		if (typeof fun !== "function") {
			throw new TypeError();
		}

		var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
		for (var i = 0; i < len; i++) {
			if (i in t) {
				fun.call(thisArg, t[i], i, t);
			}
		}
	};
}

if (!Array.prototype.map)
{
  Array.prototype.map = function(fun /*, thisArg */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var res = new Array(len);
    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      // NOTE: Absolute correctness would demand Object.defineProperty
      //       be used.  But this method is fairly new, and failure is
      //       possible only if Object.prototype or Array.prototype
      //       has a property |i| (very unlikely), so use a less-correct
      //       but more portable alternative.
      if (i in t)
        res[i] = fun.call(thisArg, t[i], i, t);
    }

    return res;
  };
};var Console = (function () {
	// compatibility
	var browser = {};
	browser.isFirefox = /firefox/i.test(navigator.userAgent);
	browser.isIE = document.documentMode;

	var support = {};
	support.consoleApply = !browser.isIE || document.documentMode && document.documentMode > 9;
	support.functionGetters = support.consoleApply;
	support.console = !!window.console;
	support.modifiedConsole = !browser.isIE && support.console && console.log.toString().indexOf('apply') !== -1;
	support.consoleStyles = !!window.chrome || !!(browser.isFirefox && support.modifiedConsole);
	support.consoleGroups = !!(window.console && console.group);

	var consoleMethodNames = ['log', 'group', 'groupCollapsed', 'groupEnd', 'warn', 'info'],
		groupDepth = 0;

	// preserve original console
	if (!support.console) {
		window.console = {};
	}

	var consoleReference = window.console;
		consoleMethodReferences = {};

	consoleMethodNames.forEach(function (name) {
		if (consoleReference[name]) {
			consoleMethodReferences[name] = consoleReference[name];
		}
	});

	if (browser.isFirefox && !support.modifiedConsole) {
		support.consoleGroups = false;
		support.consoleApply = true;
	}

	// general way to calling console methods
	function applyConsoleMethod (method, args) {
		if (!support.console) {
			return;
		}

		args = Array.prototype.slice.call(args);

		args = Console.styles.argumentsToConsoleArguments(args);

		// groupEnd should only be proxied if its actually supported
		if (!support.consoleGroups && method === 'groupEnd') {
			return;
		}

		// if a method is not supported it falls back to a standard log
		if (!consoleMethodReferences[method]) {
			method = 'log';
		}

		if (support.consoleApply) {
			return consoleMethodReferences[method].apply(consoleReference, args);
		} else {
			var message = args.join(' ');

			if (!message.match('<STYLES:UNSUPPORTED>')) {
				return consoleMethodReferences[method](args.join(' '));
			} else {
				return '<STYLES:UNSUPPORTED>';
			}
		}
	}

	function prependGroupPaddingToArguments (args) {
		var string = '';

		for (var i = 0; i < groupDepth; i++) {
			string += '-';
		}

		if (string) {
			args = args.splice(0, 0, string);
		}
	}

	// public interface
	return {
		log: function () {
			return applyConsoleMethod('log', arguments);
		},

		group: function () {
			var args = Array.prototype.slice.call(arguments);

			groupDepth++;

			if (!support.consoleGroups) {
				prependGroupPaddingToArguments(args);
			}

			return applyConsoleMethod('group', args);
		},

		groupCollapsed: function () {
			var args = Array.prototype.slice.call(arguments);

			groupDepth++;

			if (!support.consoleGroups) {
				prependGroupPaddingToArguments(args);
			}

			return applyConsoleMethod('groupCollapsed', args);
		},

		groupEnd: function () {
			groupDepth--;

			return applyConsoleMethod('groupEnd', arguments);
		},

		warn: function () {
			return applyConsoleMethod('warn', arguments);
		},

		info: function () {
			return applyConsoleMethod('info', arguments);
		},

		attach: function () {
			consoleMethodNames.forEach(function (method) {
				if (support.console) {
					window.console['_' + method] = consoleMethodReferences[method];
					window.console[method] = this[method];
				} else {
					window.console[method] = function () {};
				}
			}, this);
		},

		detach: function () {
			if (support.console) {
				consoleMethodNames.forEach(function (method) {
					delete window.console['_' + method];
					window.console[method] = consoleMethodReferences[method];
				}, this);
			} else {
				delete window.console;
			}
		},

		support: support,

		consoleMethodReferences: consoleMethodReferences,

		getFileAndLineNumber: function (caller, offset) {
			var stack = new Console.Stack(),
				line = stack.getLineByCaller(caller, offset);

			if (line) {
				return line.fileName + ':' + line.lineNumber + ' ';
			} else {
				return '';
			}
		}
	};
})();

module.exports = Console;
;Console.styles = (function () {
	var existingSpanRegExp = /^<span style="([^"]+)">.+<\/span>$/,
		spanOpenRegExp = /^<span style="([^"]+)">/,
		spanOpenOrCloseRegExp = /<span style="[^"]+">|<\/span>/g,
		styles = {},
		attached = false;

	function attach () {
		attached = true;
	}

	function register () {
		if (typeof arguments[0] === 'object') {
			var styles = arguments[0];

			for (var name in styles) {
				if (!styles.hasOwnProperty(name)) return;
				registerStyle(name, styles[name]);
			}
		} else {
			registerStyle(arguments[0], arguments[1]);
		}
	}

	function registerStyle (name, style) {
		styles[name] = style;

		function getter () {
			return format(this.toString(), name);
		}

		if (attached) {
			if (Object.defineProperty && Console.support.functionGetters) {
				Object.defineProperty(String.prototype, name, {get: getter});
			} else if (String.prototype.__defineGetter__) {
				String.prototype.__defineGetter__(name, getter);
			} else {
				String.prototype[name] = '<STYLES:UNSUPPORTED>';
			}
		}
	}

	function format (string, names) {
		if (Console.support.consoleStyles) {
			names.split(',').forEach(function (name) {
				var style = styles[name];

				if (existingSpanRegExp.test(string)) {
					string = string.replace(existingSpanRegExp, function (match, styles) {
						if (!styles.match(style)) {
							return match.replace(spanOpenRegExp, '<span style="' + styles + style + ';">');
						} else {
							return match;
						}
					});
				} else {
					string = '<span style="' + style + ';">' + string + '</span>';
				}
			});
		}

		return string;
	}

	function stringToFormatArray (string) {
		var colors = [];

		string = string.replace(spanOpenOrCloseRegExp, function (tag) {
			var styleMatch = tag.match(spanOpenRegExp);

			if (styleMatch) {
				colors.push(styleMatch[1]);
			} else {
				colors.push('');
			}

			return '%c';
		});

		return [string].concat(colors);
	}

	function argumentsToConsoleArguments (args) {
		var params = [];

		args.forEach(function (arg) {
			if (typeof arg === 'string') {
				params = params.concat(stringToFormatArray(arg));
			} else {
				params.push(arg);
			}
		});

		return params;
	}

	return {
		attach: attach,
		format: format,
		register: register,
		argumentsToConsoleArguments: argumentsToConsoleArguments
	};
})();;Console.Stack = function (stack) {
	this._stackString = stack || new Error().stack || '';
};
Console.Stack.prototype = {
	_geckoStackWithMethodNameRegExp: /\b([a-z0-9_-]+)@.*\/([^\/]*)\:(\d*)$/i,
	_geckoStackWithoutMethodName: /@.*\/([^\/]+)\:(\d*)$/i,

	_webkitStackWithMethodNameRegExp: /.+\b([a-z0-9_-]+) \(.*\/([^\/]*)\:(\d*)\:(\d+)\)$/i,
	_webkitStackWithoutMethodName: /at .*\/([^\/]*)\:(\d*)\:(\d+)/i,

	parse: function () {
		var stack = this._stackString;

		// convert stack into an array
		stack = stack.split('\n');

		// pop off first item
		stack = stack.slice(1);

		// parse stack
		stack = stack.map(function (line) {
			return this._parseStackLine(line);
		}, this);

		return stack || null;
	},

	_parseStackLine: function (line) {
		var parsedLine,
			userAgent = navigator.userAgent;

		if (userAgent.match(/Webkit/i)) {
		 	parsedLine = this._webkitParseStackLine(line);
		} else if (userAgent.match(/Gecko/i)) {
			parsedLine = this._geckoParseStackLine(line);
		}
		return parsedLine || {string: line};
	},

	_geckoParseStackLine: function (line) {
		var match;

		if (this._geckoStackWithMethodNameRegExp.test(line)) {
			match = line.match(this._geckoStackWithMethodNameRegExp);

			return {
				methodName: match[1],
				fileName: match[2],
				lineNumber: match[3]
			};
		} else if (this._geckoStackWithoutMethodName.test(line)) {
			match = line.match(this._geckoStackWithoutMethodName);

			return {
				fileName: match[1],
				lineNumber: match[2]
			};
		}
	},

	_webkitParseStackLine: function (line) {
		var match;

		if (this._webkitStackWithMethodNameRegExp.test(line)) {
			match = line.match(this._webkitStackWithMethodNameRegExp);

			return {
				methodName: match[1],
				fileName: match[2],
				lineNumber: match[3],
				columnNumber: match[4]
			};
		} else if (this._webkitStackWithoutMethodName.test(line)) {
			match = line.match(this._webkitStackWithoutMethodName);

			return {
				fileName: match[1],
				lineNumber: match[2],
				columnNumber: match[3]
			};
		}
	},

	getLineByCaller: function (caller, offset) {
		offset = offset || 0;

		var stack = this.parse();

		if (!stack) {
			return '';
		}

		for (var i = 0; i < stack.length; i++) {
			if (stack[i] && caller === stack[i].methodName) {
				return stack[i+offset];
			}
		}

		return null;
	}
};
},{}],24:[function(require,module,exports){
/*

 Software License Agreement (BSD License)
 http://taffydb.com
 Copyright (c)
 All rights reserved.


 Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following condition is met:

 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 */

/*jslint        browser : true, continue : true,
 devel  : true, indent  : 2,    maxerr   : 500,
 newcap : true, nomen   : true, plusplus : true,
 regexp : true, sloppy  : true, vars     : false,
 white  : true
*/

// BUILD 193d48d, modified by mmikowski to pass jslint

// Setup TAFFY name space to return an object with methods
var TAFFY, exports, T;
(function () {
  'use strict';
  var
    typeList,     makeTest,     idx,    typeKey,
    version,      TC,           idpad,  cmax,
    API,          protectJSON,  each,   eachin,
    isIndexable,  returnFilter, runFilters,
    numcharsplit, orderByCol,   run,    intersection,
    filter,       makeCid,      safeForJson,
    isRegexp, sortArgs
    ;
    
    
  if ( ! TAFFY ){
    // TC = Counter for Taffy DBs on page, used for unique IDs
    // cmax = size of charnumarray conversion cache
    // idpad = zeros to pad record IDs with
    version = '2.7';
    TC      = 1;
    idpad   = '000000';
    cmax    = 1000;
    API     = {};

    sortArgs = function(args) {
      var v = Array.prototype.slice.call(args);
      return v.sort();
    }

    protectJSON = function ( t ) {
      // ****************************************
      // *
      // * Takes: a variable
      // * Returns: the variable if object/array or the parsed variable if JSON
      // *
      // ****************************************  
      if ( TAFFY.isArray( t ) || TAFFY.isObject( t ) ){
        return t;
      }
      else {
        return JSON.parse( t );
      }
    };
    
    // gracefully stolen from underscore.js
    intersection = function(array1, array2) {
        return filter(array1, function(item) {
          return array2.indexOf(item) >= 0;
        });
    };

    // gracefully stolen from underscore.js
    filter = function(obj, iterator, context) {
        var results = [];
        if (obj == null) return results;
        if (Array.prototype.filter && obj.filter === Array.prototype.filter) return obj.filter(iterator, context);
        each(obj, function(value, index, list) {
          if (iterator.call(context, value, index, list)) results[results.length] = value;
        });
        return results;
    };
    
    isRegexp = function(aObj) {
        return Object.prototype.toString.call(aObj)==='[object RegExp]';
    }
    
    safeForJson = function(aObj) {
        var myResult = T.isArray(aObj) ? [] : T.isObject(aObj) ? {} : null;
        if(aObj===null) return aObj;
        for(var i in aObj) {
            myResult[i]  = isRegexp(aObj[i]) ? aObj[i].toString() : T.isArray(aObj[i]) || T.isObject(aObj[i]) ? safeForJson(aObj[i]) : aObj[i];
        }
        return myResult;
    }
    
    makeCid = function(aContext) {
        var myCid = JSON.stringify(aContext);
        if(myCid.match(/regex/)===null) return myCid;
        return JSON.stringify(safeForJson(aContext));
    }
    
    each = function ( a, fun, u ) {
      var r, i, x, y;
      // ****************************************
      // *
      // * Takes:
      // * a = an object/value or an array of objects/values
      // * f = a function
      // * u = optional flag to describe how to handle undefined values
      //   in array of values. True: pass them to the functions,
      //   False: skip. Default False;
      // * Purpose: Used to loop over arrays
      // *
      // ****************************************  
      if ( a && ((T.isArray( a ) && a.length === 1) || (!T.isArray( a ))) ){
        fun( (T.isArray( a )) ? a[0] : a, 0 );
      }
      else {
        for ( r, i, x = 0, a = (T.isArray( a )) ? a : [a], y = a.length;
              x < y; x++ )
        {
          i = a[x];
          if ( !T.isUndefined( i ) || (u || false) ){
            r = fun( i, x );
            if ( r === T.EXIT ){
              break;
            }

          }
        }
      }
    };

    eachin = function ( o, fun ) {
      // ****************************************
      // *
      // * Takes:
      // * o = an object
      // * f = a function
      // * Purpose: Used to loop over objects
      // *
      // ****************************************  
      var x = 0, r, i;

      for ( i in o ){
        if ( o.hasOwnProperty( i ) ){
          r = fun( o[i], i, x++ );
          if ( r === T.EXIT ){
            break;
          }
        }
      }

    };

    API.extend = function ( m, f ) {
      // ****************************************
      // *
      // * Takes: method name, function
      // * Purpose: Add a custom method to the API
      // *
      // ****************************************  
      API[m] = function () {
        return f.apply( this, sortArgs(arguments) );
      };
    };

    isIndexable = function ( f ) {
      var i;
      // Check to see if record ID
      if ( T.isString( f ) && /[t][0-9]*[r][0-9]*/i.test( f ) ){
        return true;
      }
      // Check to see if record
      if ( T.isObject( f ) && f.___id && f.___s ){
        return true;
      }

      // Check to see if array of indexes
      if ( T.isArray( f ) ){
        i = true;
        each( f, function ( r ) {
          if ( !isIndexable( r ) ){
            i = false;

            return TAFFY.EXIT;
          }
        });
        return i;
      }

      return false;
    };

    runFilters = function ( r, filter ) {
      // ****************************************
      // *
      // * Takes: takes a record and a collection of filters
      // * Returns: true if the record matches, false otherwise
      // ****************************************
      var match = true;


      each( filter, function ( mf ) {
        switch ( T.typeOf( mf ) ){
          case 'function':
            // run function
            if ( !mf.apply( r ) ){
              match = false;
              return TAFFY.EXIT;
            }
            break;
          case 'array':
            // loop array and treat like a SQL or
            match = (mf.length === 1) ? (runFilters( r, mf[0] )) :
              (mf.length === 2) ? (runFilters( r, mf[0] ) ||
                runFilters( r, mf[1] )) :
                (mf.length === 3) ? (runFilters( r, mf[0] ) ||
                  runFilters( r, mf[1] ) || runFilters( r, mf[2] )) :
                  (mf.length === 4) ? (runFilters( r, mf[0] ) ||
                    runFilters( r, mf[1] ) || runFilters( r, mf[2] ) ||
                    runFilters( r, mf[3] )) : false;
            if ( mf.length > 4 ){
              each( mf, function ( f ) {
                if ( runFilters( r, f ) ){
                  match = true;
                }
              });
            }
            break;
        }
      });

      return match;
    };

    returnFilter = function ( f ) {
      // ****************************************
      // *
      // * Takes: filter object
      // * Returns: a filter function
      // * Purpose: Take a filter object and return a function that can be used to compare
      // * a TaffyDB record to see if the record matches a query
      // ****************************************  
      var nf = [];
      if ( T.isString( f ) && /[t][0-9]*[r][0-9]*/i.test( f ) ){
        f = { ___id : f };
      }
      if ( T.isArray( f ) ){
        // if we are working with an array

        each( f, function ( r ) {
          // loop the array and return a filter func for each value
          nf.push( returnFilter( r ) );
        });
        // now build a func to loop over the filters and return true if ANY of the filters match
        // This handles logical OR expressions
        f = function () {
          var that = this, match = false;
          each( nf, function ( f ) {
            if ( runFilters( that, f ) ){
              match = true;
            }
          });
          return match;
        };
        return f;

      }
      // if we are dealing with an Object
      if ( T.isObject( f ) ){
        if ( T.isObject( f ) && f.___id && f.___s ){
          f = { ___id : f.___id };
        }

        // Loop over each value on the object to prep match type and match value
        eachin( f, function ( v, i ) {

          // default match type to IS/Equals
          if ( !T.isObject( v ) ){
            v = {
              'is' : v
            };
          }
          // loop over each value on the value object  - if any
          eachin( v, function ( mtest, s ) {
            // s = match type, e.g. is, hasAll, like, etc
            var c = [], looper;

            // function to loop and apply filter
            looper = (s === 'hasAll') ?
              function ( mtest, func ) {
                func( mtest );
              } : each;

            // loop over each test
            looper( mtest, function ( mtest ) {

              // su = match success
              // f = match false
              var su = true, f = false, matchFunc;


              // push a function onto the filter collection to do the matching
              matchFunc = function () {

                // get the value from the record
                var
                  mvalue   = this[i],
                  eqeq     = '==',
                  bangeq   = '!=',
                  eqeqeq   = '===',
                  lt   = '<',
                  gt   = '>',
                  lteq   = '<=',
                  gteq   = '>=',
                  bangeqeq = '!==',
                  r
                  ;

                if (typeof mvalue === 'undefined') {
                  return false;
                }
                
                if ( (s.indexOf( '!' ) === 0) && s !== bangeq &&
                  s !== bangeqeq )
                {
                  // if the filter name starts with ! as in '!is' then reverse the match logic and remove the !
                  su = false;
                  s = s.substring( 1, s.length );
                }
                // get the match results based on the s/match type
                /*jslint eqeq : true */
                r = (
                  (s === 'regex') ? (mtest.test( mvalue )) : (s === 'lt' || s === lt)
                  ? (mvalue < mtest)  : (s === 'gt' || s === gt)
                  ? (mvalue > mtest)  : (s === 'lte' || s === lteq)
                  ? (mvalue <= mtest) : (s === 'gte' || s === gteq)
                  ? (mvalue >= mtest) : (s === 'left')
                  ? (mvalue.indexOf( mtest ) === 0) : (s === 'leftnocase')
                  ? (mvalue.toLowerCase().indexOf( mtest.toLowerCase() )
                    === 0) : (s === 'right')
                  ? (mvalue.substring( (mvalue.length - mtest.length) )
                    === mtest) : (s === 'rightnocase')
                  ? (mvalue.toLowerCase().substring(
                    (mvalue.length - mtest.length) ) === mtest.toLowerCase())
                    : (s === 'like')
                  ? (mvalue.indexOf( mtest ) >= 0) : (s === 'likenocase')
                  ? (mvalue.toLowerCase().indexOf(mtest.toLowerCase()) >= 0)
                    : (s === eqeqeq || s === 'is')
                  ? (mvalue ===  mtest) : (s === eqeq)
                  ? (mvalue == mtest) : (s === bangeqeq)
                  ? (mvalue !==  mtest) : (s === bangeq)
                  ? (mvalue != mtest) : (s === 'isnocase')
                  ? (mvalue.toLowerCase
                    ? mvalue.toLowerCase() === mtest.toLowerCase()
                      : mvalue === mtest) : (s === 'has')
                  ? (T.has( mvalue, mtest )) : (s === 'hasall')
                  ? (T.hasAll( mvalue, mtest )) : (s === 'contains')
                  ? (TAFFY.isArray(mvalue) && mvalue.indexOf(mtest) > -1) : (
                    s.indexOf( 'is' ) === -1
                      && !TAFFY.isNull( mvalue )
                      && !TAFFY.isUndefined( mvalue )
                      && !TAFFY.isObject( mtest )
                      && !TAFFY.isArray( mtest )
                    )
                  ? (mtest === mvalue[s])
                    : (T[s] && T.isFunction( T[s] )
                    && s.indexOf( 'is' ) === 0)
                  ? T[s]( mvalue ) === mtest
                    : (T[s] && T.isFunction( T[s] ))
                  ? T[s]( mvalue, mtest ) : (false)
                );
                /*jslint eqeq : false */
                r = (r && !su) ? false : (!r && !su) ? true : r;

                return r;
              };
              c.push( matchFunc );

            });
            // if only one filter in the collection push it onto the filter list without the array
            if ( c.length === 1 ){

              nf.push( c[0] );
            }
            else {
              // else build a function to loop over all the filters and return true only if ALL match
              // this is a logical AND
              nf.push( function () {
                var that = this, match = false;
                each( c, function ( f ) {
                  if ( f.apply( that ) ){
                    match = true;
                  }
                });
                return match;
              });
            }
          });
        });
        // finally return a single function that wraps all the other functions and will run a query
        // where all functions have to return true for a record to appear in a query result
        f = function () {
          var that = this, match = true;
          // faster if less than  4 functions
          match = (nf.length === 1 && !nf[0].apply( that )) ? false :
            (nf.length === 2 &&
              (!nf[0].apply( that ) || !nf[1].apply( that ))) ? false :
              (nf.length === 3 &&
                (!nf[0].apply( that ) || !nf[1].apply( that ) ||
                  !nf[2].apply( that ))) ? false :
                (nf.length === 4 &&
                  (!nf[0].apply( that ) || !nf[1].apply( that ) ||
                    !nf[2].apply( that ) || !nf[3].apply( that ))) ? false
                  : true;
          if ( nf.length > 4 ){
            each( nf, function ( f ) {
              if ( !runFilters( that, f ) ){
                match = false;
              }
            });
          }
          return match;
        };
        return f;
      }

      // if function
      if ( T.isFunction( f ) ){
        return f;
      }
    };

    orderByCol = function ( ar, o ) {
      // ****************************************
      // *
      // * Takes: takes an array and a sort object
      // * Returns: the array sorted
      // * Purpose: Accept filters such as "[col], [col2]" or "[col] desc" and sort on those columns
      // *
      // ****************************************

      var sortFunc = function ( a, b ) {
        // function to pass to the native array.sort to sort an array
        var r = 0;

        T.each( o, function ( sd ) {
          // loop over the sort instructions
          // get the column name
          var o, col, dir, c, d;
          o = sd.split( ' ' );
          col = o[0];

          // get the direction
          dir = (o.length === 1) ? "logical" : o[1];


          if ( dir === 'logical' ){
            // if dir is logical than grab the charnum arrays for the two values we are looking at
            c = numcharsplit( a[col] );
            d = numcharsplit( b[col] );
            // loop over the charnumarrays until one value is higher than the other
            T.each( (c.length <= d.length) ? c : d, function ( x, i ) {
              if ( c[i] < d[i] ){
                r = -1;
                return TAFFY.EXIT;
              }
              else if ( c[i] > d[i] ){
                r = 1;
                return TAFFY.EXIT;
              }
            } );
          }
          else if ( dir === 'logicaldesc' ){
            // if logicaldesc than grab the charnum arrays for the two values we are looking at
            c = numcharsplit( a[col] );
            d = numcharsplit( b[col] );
            // loop over the charnumarrays until one value is lower than the other
            T.each( (c.length <= d.length) ? c : d, function ( x, i ) {
              if ( c[i] > d[i] ){
                r = -1;
                return TAFFY.EXIT;
              }
              else if ( c[i] < d[i] ){
                r = 1;
                return TAFFY.EXIT;
              }
            } );
          }
          else if ( dir === 'asec' && a[col] < b[col] ){
            // if asec - default - check to see which is higher
            r = -1;
            return T.EXIT;
          }
          else if ( dir === 'asec' && a[col] > b[col] ){
            // if asec - default - check to see which is higher
            r = 1;
            return T.EXIT;
          }
          else if ( dir === 'desc' && a[col] > b[col] ){
            // if desc check to see which is lower
            r = -1;
            return T.EXIT;

          }
          else if ( dir === 'desc' && a[col] < b[col] ){
            // if desc check to see which is lower
            r = 1;
            return T.EXIT;

          }
          // if r is still 0 and we are doing a logical sort than look to see if one array is longer than the other
          if ( r === 0 && dir === 'logical' && c.length < d.length ){
            r = -1;
          }
          else if ( r === 0 && dir === 'logical' && c.length > d.length ){
            r = 1;
          }
          else if ( r === 0 && dir === 'logicaldesc' && c.length > d.length ){
            r = -1;
          }
          else if ( r === 0 && dir === 'logicaldesc' && c.length < d.length ){
            r = 1;
          }

          if ( r !== 0 ){
            return T.EXIT;
          }


        } );
        return r;
      };
      // call the sort function and return the newly sorted array
      return (ar && ar.push) ? ar.sort( sortFunc ) : ar;


    };

    // ****************************************
    // *
    // * Takes: a string containing numbers and letters and turn it into an array
    // * Returns: return an array of numbers and letters
    // * Purpose: Used for logical sorting. String Example: 12ABC results: [12,'ABC']
    // **************************************** 
    (function () {
      // creates a cache for numchar conversions
      var cache = {}, cachcounter = 0;
      // creates the numcharsplit function
      numcharsplit = function ( thing ) {
        // if over 1000 items exist in the cache, clear it and start over
        if ( cachcounter > cmax ){
          cache = {};
          cachcounter = 0;
        }

        // if a cache can be found for a numchar then return its array value
        return cache['_' + thing] || (function () {
          // otherwise do the conversion
          // make sure it is a string and setup so other variables
          var nthing = String( thing ),
            na = [],
            rv = '_',
            rt = '',
            x, xx, c;

          // loop over the string char by char
          for ( x = 0, xx = nthing.length; x < xx; x++ ){
            // take the char at each location
            c = nthing.charCodeAt( x );
            // check to see if it is a valid number char and append it to the array.
            // if last char was a string push the string to the charnum array
            if ( ( c >= 48 && c <= 57 ) || c === 46 ){
              if ( rt !== 'n' ){
                rt = 'n';
                na.push( rv.toLowerCase() );
                rv = '';
              }
              rv = rv + nthing.charAt( x );
            }
            else {
              // check to see if it is a valid string char and append to string
              // if last char was a number push the whole number to the charnum array
              if ( rt !== 's' ){
                rt = 's';
                na.push( parseFloat( rv ) );
                rv = '';
              }
              rv = rv + nthing.charAt( x );
            }
          }
          // once done, push the last value to the charnum array and remove the first uneeded item
          na.push( (rt === 'n') ? parseFloat( rv ) : rv.toLowerCase() );
          na.shift();
          // add to cache
          cache['_' + thing] = na;
          cachcounter++;
          // return charnum array
          return na;
        }());
      };
    }());

    // ****************************************
    // *
    // * Runs a query
    // **************************************** 


    run = function () {
      this.context( {
        results : this.getDBI().query( this.context() )
      });

    };

    API.extend( 'filter', function () {
      // ****************************************
      // *
      // * Takes: takes unlimited filter objects as arguments
      // * Returns: method collection
      // * Purpose: Take filters as objects and cache functions for later lookup when a query is run
      // **************************************** 
      var
        nc = TAFFY.mergeObj( this.context(), { run : null } ),
        nq = []
      ;
      each( nc.q, function ( v ) {
        nq.push( v );
      });
      nc.q = nq;
      // Hadnle passing of ___ID or a record on lookup.
      each( sortArgs(arguments), function ( f ) {
        nc.q.push( returnFilter( f ) );
        nc.filterRaw.push( f );
      });

      return this.getroot( nc );
    });

    API.extend( 'order', function ( o ) {
      // ****************************************
      // *
      // * Purpose: takes a string and creates an array of order instructions to be used with a query
      // ****************************************

      o = o.split( ',' );
      var x = [], nc;

      each( o, function ( r ) {
        x.push( r.replace( /^\s*/, '' ).replace( /\s*$/, '' ) );
      });

      nc = TAFFY.mergeObj( this.context(), {sort : null} );
      nc.order = x;

      return this.getroot( nc );
    });

    API.extend( 'limit', function ( n ) {
      // ****************************************
      // *
      // * Purpose: takes a limit number to limit the number of rows returned by a query. Will update the results
      // * of a query
      // **************************************** 
      var nc = TAFFY.mergeObj( this.context(), {}),
        limitedresults
        ;

      nc.limit = n;

      if ( nc.run && nc.sort ){
        limitedresults = [];
        each( nc.results, function ( i, x ) {
          if ( (x + 1) > n ){
            return TAFFY.EXIT;
          }
          limitedresults.push( i );
        });
        nc.results = limitedresults;
      }

      return this.getroot( nc );
    });

    API.extend( 'start', function ( n ) {
      // ****************************************
      // *
      // * Purpose: takes a limit number to limit the number of rows returned by a query. Will update the results
      // * of a query
      // **************************************** 
      var nc = TAFFY.mergeObj( this.context(), {} ),
        limitedresults
        ;

      nc.start = n;

      if ( nc.run && nc.sort && !nc.limit ){
        limitedresults = [];
        each( nc.results, function ( i, x ) {
          if ( (x + 1) > n ){
            limitedresults.push( i );
          }
        });
        nc.results = limitedresults;
      }
      else {
        nc = TAFFY.mergeObj( this.context(), {run : null, start : n} );
      }

      return this.getroot( nc );
    });

    API.extend( 'update', function ( arg0, arg1, arg2 ) {
      // ****************************************
      // *
      // * Takes: a object and passes it off DBI update method for all matched records
      // **************************************** 
      var runEvent = true, o = {}, args = sortArgs(arguments), that;
      if ( TAFFY.isString( arg0 ) &&
        (arguments.length === 2 || arguments.length === 3) )
      {
        o[arg0] = arg1;
        if ( arguments.length === 3 ){
          runEvent = arg2;
        }
      }
      else {
        o = arg0;
        if ( args.length === 2 ){
          runEvent = arg1;
        }
      }

      that = this;
      run.call( this );
      each( this.context().results, function ( r ) {
        var c = o;
        if ( TAFFY.isFunction( c ) ){
          c = c.apply( TAFFY.mergeObj( r, {} ) );
        }
        else {
          if ( T.isFunction( c ) ){
            c = c( TAFFY.mergeObj( r, {} ) );
          }
        }
        if ( TAFFY.isObject( c ) ){
          that.getDBI().update( r.___id, c, runEvent );
        }
      });
      if ( this.context().results.length ){
        this.context( { run : null });
      }
      return this;
    });
    API.extend( 'remove', function ( runEvent ) {
      // ****************************************
      // *
      // * Purpose: removes records from the DB via the remove and removeCommit DBI methods
      // **************************************** 
      var that = this, c = 0;
      run.call( this );
      each( this.context().results, function ( r ) {
        that.getDBI().remove( r.___id );
        c++;
      });
      if ( this.context().results.length ){
        this.context( {
          run : null
        });
        that.getDBI().removeCommit( runEvent );
      }

      return c;
    });


    API.extend( 'count', function () {
      // ****************************************
      // *
      // * Returns: The length of a query result
      // **************************************** 
      run.call( this );
      return this.context().results.length;
    });

    API.extend( 'callback', function ( f, delay ) {
      // ****************************************
      // *
      // * Returns null;
      // * Runs a function on return of run.call
      // **************************************** 
      if ( f ){
        var that = this;
        setTimeout( function () {
          run.call( that );
          f.call( that.getroot( that.context() ) );
        }, delay || 0 );
      }


      return null;
    });

    API.extend( 'get', function () {
      // ****************************************
      // *
      // * Returns: An array of all matching records
      // **************************************** 
      run.call( this );
      return this.context().results;
    });

    API.extend( 'stringify', function () {
      // ****************************************
      // *
      // * Returns: An JSON string of all matching records
      // **************************************** 
      return JSON.stringify( this.get() );
    });
    API.extend( 'first', function () {
      // ****************************************
      // *
      // * Returns: The first matching record
      // **************************************** 
      run.call( this );
      return this.context().results[0] || false;
    });
    API.extend( 'last', function () {
      // ****************************************
      // *
      // * Returns: The last matching record
      // **************************************** 
      run.call( this );
      return this.context().results[this.context().results.length - 1] ||
        false;
    });


    API.extend( 'sum', function () {
      // ****************************************
      // *
      // * Takes: column to sum up
      // * Returns: Sums the values of a column
      // **************************************** 
      var total = 0, that = this;
      run.call( that );
      each( sortArgs(arguments), function ( c ) {
        each( that.context().results, function ( r ) {
          total = total + (r[c] || 0);
        });
      });
      return total;
    });

    API.extend( 'min', function ( c ) {
      // ****************************************
      // *
      // * Takes: column to find min
      // * Returns: the lowest value
      // **************************************** 
      var lowest = null;
      run.call( this );
      each( this.context().results, function ( r ) {
        if ( lowest === null || r[c] < lowest ){
          lowest = r[c];
        }
      });
      return lowest;
    });

    //  Taffy innerJoin Extension (OCD edition)
    //  =======================================
    //
    //  How to Use
    //  **********
    //
    //  left_table.innerJoin( right_table, condition1 <,... conditionN> )
    //
    //  A condition can take one of 2 forms:
    //
    //    1. An ARRAY with 2 or 3 values:
    //    A column name from the left table, an optional comparison string,
    //    and column name from the right table.  The condition passes if the test
    //    indicated is true.   If the condition string is omitted, '===' is assumed.
    //    EXAMPLES: [ 'last_used_time', '>=', 'current_use_time' ], [ 'user_id','id' ]
    //
    //    2. A FUNCTION:
    //    The function receives a left table row and right table row during the
    //    cartesian join.  If the function returns true for the rows considered,
    //    the merged row is included in the result set.
    //    EXAMPLE: function (l,r){ return l.name === r.label; }
    //
    //  Conditions are considered in the order they are presented.  Therefore the best
    //  performance is realized when the least expensive and highest prune-rate
    //  conditions are placed first, since if they return false Taffy skips any
    //  further condition tests.
    //
    //  Other notes
    //  ***********
    //
    //  This code passes jslint with the exception of 2 warnings about
    //  the '==' and '!=' lines.  We can't do anything about that short of
    //  deleting the lines.
    //
    //  Credits
    //  *******
    //
    //  Heavily based upon the work of Ian Toltz.
    //  Revisions to API by Michael Mikowski.
    //  Code convention per standards in http://manning.com/mikowski
    (function () {
      var innerJoinFunction = (function () {
        var fnCompareList, fnCombineRow, fnMain;

        fnCompareList = function ( left_row, right_row, arg_list ) {
          var data_lt, data_rt, op_code, error;

          if ( arg_list.length === 2 ){
            data_lt = left_row[arg_list[0]];
            op_code = '===';
            data_rt = right_row[arg_list[1]];
          }
          else {
            data_lt = left_row[arg_list[0]];
            op_code = arg_list[1];
            data_rt = right_row[arg_list[2]];
          }

          /*jslint eqeq : true */
          switch ( op_code ){
            case '===' :
              return data_lt === data_rt;
            case '!==' :
              return data_lt !== data_rt;
            case '<'   :
              return data_lt < data_rt;
            case '>'   :
              return data_lt > data_rt;
            case '<='  :
              return data_lt <= data_rt;
            case '>='  :
              return data_lt >= data_rt;
            case '=='  :
              return data_lt == data_rt;
            case '!='  :
              return data_lt != data_rt;
            default :
              throw String( op_code ) + ' is not supported';
          }
          // 'jslint eqeq : false'  here results in
          // "Unreachable '/*jslint' after 'return'".
          // We don't need it though, as the rule exception
          // is discarded at the end of this functional scope
        };

        fnCombineRow = function ( left_row, right_row ) {
          var out_map = {}, i, prefix;

          for ( i in left_row ){
            if ( left_row.hasOwnProperty( i ) ){
              out_map[i] = left_row[i];
            }
          }
          for ( i in right_row ){
            if ( right_row.hasOwnProperty( i ) && i !== '___id' &&
              i !== '___s' )
            {
              prefix = !TAFFY.isUndefined( out_map[i] ) ? 'right_' : '';
              out_map[prefix + String( i ) ] = right_row[i];
            }
          }
          return out_map;
        };

        fnMain = function ( table ) {
          var
            right_table, i,
            arg_list = sortArgs(arguments),
            arg_length = arg_list.length,
            result_list = []
            ;

          if ( typeof table.filter !== 'function' ){
            if ( table.TAFFY ){ right_table = table(); }
            else {
              throw 'TAFFY DB or result not supplied';
            }
          }
          else { right_table = table; }

          this.context( {
            results : this.getDBI().query( this.context() )
          } );

          TAFFY.each( this.context().results, function ( left_row ) {
            right_table.each( function ( right_row ) {
              var arg_data, is_ok = true;
              CONDITION:
                for ( i = 1; i < arg_length; i++ ){
                  arg_data = arg_list[i];
                  if ( typeof arg_data === 'function' ){
                    is_ok = arg_data( left_row, right_row );
                  }
                  else if ( typeof arg_data === 'object' && arg_data.length ){
                    is_ok = fnCompareList( left_row, right_row, arg_data );
                  }
                  else {
                    is_ok = false;
                  }

                  if ( !is_ok ){ break CONDITION; } // short circuit
                }

              if ( is_ok ){
                result_list.push( fnCombineRow( left_row, right_row ) );
              }
            } );
          } );
          return TAFFY( result_list )();
        };

        return fnMain;
      }());

      API.extend( 'join', innerJoinFunction );
    }());

    API.extend( 'max', function ( c ) {
      // ****************************************
      // *
      // * Takes: column to find max
      // * Returns: the highest value
      // ****************************************
      var highest = null;
      run.call( this );
      each( this.context().results, function ( r ) {
        if ( highest === null || r[c] > highest ){
          highest = r[c];
        }
      });
      return highest;
    });

    API.extend( 'select', function () {
      // ****************************************
      // *
      // * Takes: columns to select values into an array
      // * Returns: array of values
      // * Note if more than one column is given an array of arrays is returned
      // **************************************** 

      var ra = [], args = sortArgs(arguments);
      run.call( this );
      if ( arguments.length === 1 ){

        each( this.context().results, function ( r ) {

          ra.push( r[args[0]] );
        });
      }
      else {
        each( this.context().results, function ( r ) {
          var row = [];
          each( args, function ( c ) {
            row.push( r[c] );
          });
          ra.push( row );
        });
      }
      return ra;
    });
    API.extend( 'distinct', function () {
      // ****************************************
      // *
      // * Takes: columns to select unique alues into an array
      // * Returns: array of values
      // * Note if more than one column is given an array of arrays is returned
      // **************************************** 
      var ra = [], args = sortArgs(arguments);
      run.call( this );
      if ( arguments.length === 1 ){

        each( this.context().results, function ( r ) {
          var v = r[args[0]], dup = false;
          each( ra, function ( d ) {
            if ( v === d ){
              dup = true;
              return TAFFY.EXIT;
            }
          });
          if ( !dup ){
            ra.push( v );
          }
        });
      }
      else {
        each( this.context().results, function ( r ) {
          var row = [], dup = false;
          each( args, function ( c ) {
            row.push( r[c] );
          });
          each( ra, function ( d ) {
            var ldup = true;
            each( args, function ( c, i ) {
              if ( row[i] !== d[i] ){
                ldup = false;
                return TAFFY.EXIT;
              }
            });
            if ( ldup ){
              dup = true;
              return TAFFY.EXIT;
            }
          });
          if ( !dup ){
            ra.push( row );
          }
        });
      }
      return ra;
    });
    API.extend( 'supplant', function ( template, returnarray ) {
      // ****************************************
      // *
      // * Takes: a string template formated with key to be replaced with values from the rows, flag to determine if we want array of strings
      // * Returns: array of values or a string
      // **************************************** 
      var ra = [];
      run.call( this );
      each( this.context().results, function ( r ) {
        // TODO: The curly braces used to be unescaped
        ra.push( template.replace( /\{([^\{\}]*)\}/g, function ( a, b ) {
          var v = r[b];
          return typeof v === 'string' || typeof v === 'number' ? v : a;
        } ) );
      });
      return (!returnarray) ? ra.join( "" ) : ra;
    });


    API.extend( 'each', function ( m ) {
      // ****************************************
      // *
      // * Takes: a function
      // * Purpose: loops over every matching record and applies the function
      // **************************************** 
      run.call( this );
      each( this.context().results, m );
      return this;
    });
    API.extend( 'map', function ( m ) {
      // ****************************************
      // *
      // * Takes: a function
      // * Purpose: loops over every matching record and applies the function, returing the results in an array
      // **************************************** 
      var ra = [];
      run.call( this );
      each( this.context().results, function ( r ) {
        ra.push( m( r ) );
      });
      return ra;
    });



    T = function ( d ) {
      // ****************************************
      // *
      // * T is the main TAFFY object
      // * Takes: an array of objects or JSON
      // * Returns a new TAFFYDB
      // **************************************** 
      var TOb = [],
        ID = {},
        RC = 1,
        settings = {
          template          : false,
          onInsert          : false,
          onUpdate          : false,
          onRemove          : false,
          onDBChange        : false,
          storageName       : false,
          forcePropertyCase : null,
          cacheSize         : 100,
          name              : ''
        },
        dm = new Date(),
        CacheCount = 0,
        CacheClear = 0,
        Cache = {},
        DBI, runIndexes, root
        ;
      // ****************************************
      // *
      // * TOb = this database
      // * ID = collection of the record IDs and locations within the DB, used for fast lookups
      // * RC = record counter, used for creating IDs
      // * settings.template = the template to merge all new records with
      // * settings.onInsert = event given a copy of the newly inserted record
      // * settings.onUpdate = event given the original record, the changes, and the new record
      // * settings.onRemove = event given the removed record
      // * settings.forcePropertyCase = on insert force the proprty case to be lower or upper. default lower, null/undefined will leave case as is
      // * dm = the modify date of the database, used for query caching
      // **************************************** 


      runIndexes = function ( indexes ) {
        // ****************************************
        // *
        // * Takes: a collection of indexes
        // * Returns: collection with records matching indexed filters
        // **************************************** 

        var records = [], UniqueEnforce = false;

        if ( indexes.length === 0 ){
          return TOb;
        }

        each( indexes, function ( f ) {
          // Check to see if record ID
          if ( T.isString( f ) && /[t][0-9]*[r][0-9]*/i.test( f ) &&
            TOb[ID[f]] )
          {
            records.push( TOb[ID[f]] );
            UniqueEnforce = true;
          }
          // Check to see if record
          if ( T.isObject( f ) && f.___id && f.___s &&
            TOb[ID[f.___id]] )
          {
            records.push( TOb[ID[f.___id]] );
            UniqueEnforce = true;
          }
          // Check to see if array of indexes
          if ( T.isArray( f ) ){
            each( f, function ( r ) {
              each( runIndexes( r ), function ( rr ) {
                records.push( rr );
              });

            });
          }
        });
        if ( UniqueEnforce && records.length > 1 ){
          records = [];
        }

        return records;
      };

      DBI = {
        // ****************************************
        // *
        // * The DBI is the internal DataBase Interface that interacts with the data
        // **************************************** 
        dm           : function ( nd ) {
          // ****************************************
          // *
          // * Takes: an optional new modify date
          // * Purpose: used to get and set the DB modify date
          // **************************************** 
          if ( nd ){
            dm = nd;
            Cache = {};
            CacheCount = 0;
            CacheClear = 0;
          }
          if ( settings.onDBChange ){
            setTimeout( function () {
              settings.onDBChange.call( TOb );
            }, 0 );
          }
          if ( settings.storageName ){
            setTimeout( function () {
              localStorage.setItem( 'taffy_' + settings.storageName,
                JSON.stringify( TOb ) );
            });
          }
          return dm;
        },
        insert       : function ( i, runEvent ) {
          // ****************************************
          // *
          // * Takes: a new record to insert
          // * Purpose: merge the object with the template, add an ID, insert into DB, call insert event
          // **************************************** 
          var columns = [],
            records   = [],
            input     = protectJSON( i )
            ;
          each( input, function ( v, i ) {
            var nv, o;
            if ( T.isArray( v ) && i === 0 ){
              each( v, function ( av ) {

                columns.push( (settings.forcePropertyCase === 'lower')
                  ? av.toLowerCase()
                    : (settings.forcePropertyCase === 'upper')
                  ? av.toUpperCase() : av );
              });
              return true;
            }
            else if ( T.isArray( v ) ){
              nv = {};
              each( v, function ( av, ai ) {
                nv[columns[ai]] = av;
              });
              v = nv;

            }
            else if ( T.isObject( v ) && settings.forcePropertyCase ){
              o = {};

              eachin( v, function ( av, ai ) {
                o[(settings.forcePropertyCase === 'lower') ? ai.toLowerCase()
                  : (settings.forcePropertyCase === 'upper')
                  ? ai.toUpperCase() : ai] = v[ai];
              });
              v = o;
            }

            RC++;
            v.___id = 'T' + String( idpad + TC ).slice( -6 ) + 'R' +
              String( idpad + RC ).slice( -6 );
            v.___s = true;
            records.push( v.___id );
            if ( settings.template ){
              v = T.mergeObj( settings.template, v );
            }
            TOb.push( v );

            ID[v.___id] = TOb.length - 1;
            if ( settings.onInsert &&
              (runEvent || TAFFY.isUndefined( runEvent )) )
            {
              settings.onInsert.call( v );
            }
            DBI.dm( new Date() );
          });
          return root( records );
        },
        sort         : function ( o ) {
          // ****************************************
          // *
          // * Purpose: Change the sort order of the DB itself and reset the ID bucket
          // **************************************** 
          TOb = orderByCol( TOb, o.split( ',' ) );
          ID = {};
          each( TOb, function ( r, i ) {
            ID[r.___id] = i;
          });
          DBI.dm( new Date() );
          return true;
        },
        update       : function ( id, changes, runEvent ) {
          // ****************************************
          // *
          // * Takes: the ID of record being changed and the changes
          // * Purpose: Update a record and change some or all values, call the on update method
          // ****************************************

          var nc = {}, or, nr, tc, hasChange;
          if ( settings.forcePropertyCase ){
            eachin( changes, function ( v, p ) {
              nc[(settings.forcePropertyCase === 'lower') ? p.toLowerCase()
                : (settings.forcePropertyCase === 'upper') ? p.toUpperCase()
                : p] = v;
            });
            changes = nc;
          }

          or = TOb[ID[id]];
          nr = T.mergeObj( or, changes );

          tc = {};
          hasChange = false;
          eachin( nr, function ( v, i ) {
            if ( TAFFY.isUndefined( or[i] ) || or[i] !== v ){
              tc[i] = v;
              hasChange = true;
            }
          });
          if ( hasChange ){
            if ( settings.onUpdate &&
              (runEvent || TAFFY.isUndefined( runEvent )) )
            {
              settings.onUpdate.call( nr, TOb[ID[id]], tc );
            }
            TOb[ID[id]] = nr;
            DBI.dm( new Date() );
          }
        },
        remove       : function ( id ) {
          // ****************************************
          // *
          // * Takes: the ID of record to be removed
          // * Purpose: remove a record, changes its ___s value to false
          // **************************************** 
          TOb[ID[id]].___s = false;
        },
        removeCommit : function ( runEvent ) {
          var x;
          // ****************************************
          // *
          // * 
          // * Purpose: loop over all records and remove records with ___s = false, call onRemove event, clear ID
          // ****************************************
          for ( x = TOb.length - 1; x > -1; x-- ){

            if ( !TOb[x].___s ){
              if ( settings.onRemove &&
                (runEvent || TAFFY.isUndefined( runEvent )) )
              {
                settings.onRemove.call( TOb[x] );
              }
              ID[TOb[x].___id] = undefined;
              TOb.splice( x, 1 );
            }
          }
          ID = {};
          each( TOb, function ( r, i ) {
            ID[r.___id] = i;
          });
          DBI.dm( new Date() );
        },
        query : function ( context ) {
          // ****************************************
          // *
          // * Takes: the context object for a query and either returns a cache result or a new query result
          // **************************************** 
          var returnq, cid, results, indexed, limitq, ni;

          if ( settings.cacheSize ) {
            cid = '';
            each( context.filterRaw, function ( r ) {
              if ( T.isFunction( r ) ){
                cid = 'nocache';
                return TAFFY.EXIT;
              }
            });
            if ( cid === '' ){
              cid = makeCid( T.mergeObj( context,
                {q : false, run : false, sort : false} ) );
            }
          }
          // Run a new query if there are no results or the run date has been cleared
          if ( !context.results || !context.run ||
            (context.run && DBI.dm() > context.run) )
          {
            results = [];

            // check Cache

            if ( settings.cacheSize && Cache[cid] ){

              Cache[cid].i = CacheCount++;
              return Cache[cid].results;
            }
            else {
              // if no filter, return DB
              if ( context.q.length === 0 && context.index.length === 0 ){
                each( TOb, function ( r ) {
                  results.push( r );
                });
                returnq = results;
              }
              else {
                // use indexes

                indexed = runIndexes( context.index );

                // run filters
                each( indexed, function ( r ) {
                  // Run filter to see if record matches query
                  if ( context.q.length === 0 || runFilters( r, context.q ) ){
                    results.push( r );
                  }
                });

                returnq = results;
              }
            }


          }
          else {
            // If query exists and run has not been cleared return the cache results
            returnq = context.results;
          }
          // If a custom order array exists and the run has been clear or the sort has been cleared
          if ( context.order.length > 0 && (!context.run || !context.sort) ){
            // order the results
            returnq = orderByCol( returnq, context.order );
          }

          // If a limit on the number of results exists and it is less than the returned results, limit results
          if ( returnq.length &&
            ((context.limit && context.limit < returnq.length) ||
              context.start)
          ) {
            limitq = [];
            each( returnq, function ( r, i ) {
              if ( !context.start ||
                (context.start && (i + 1) >= context.start) )
              {
                if ( context.limit ){
                  ni = (context.start) ? (i + 1) - context.start : i;
                  if ( ni < context.limit ){
                    limitq.push( r );
                  }
                  else if ( ni > context.limit ){
                    return TAFFY.EXIT;
                  }
                }
                else {
                  limitq.push( r );
                }
              }
            });
            returnq = limitq;
          }

          // update cache
          if ( settings.cacheSize && cid !== 'nocache' ){
            CacheClear++;

            setTimeout( function () {
              var bCounter, nc;
              if ( CacheClear >= settings.cacheSize * 2 ){
                CacheClear = 0;
                bCounter = CacheCount - settings.cacheSize;
                nc = {};
                eachin( function ( r, k ) {
                  if ( r.i >= bCounter ){
                    nc[k] = r;
                  }
                });
                Cache = nc;
              }
            }, 0 );

            Cache[cid] = { i : CacheCount++, results : returnq };
          }
          return returnq;
        }
      };


      root = function () {
        var iAPI, context;
        // ****************************************
        // *
        // * The root function that gets returned when a new DB is created
        // * Takes: unlimited filter arguments and creates filters to be run when a query is called
        // **************************************** 
        // ****************************************
        // *
        // * iAPI is the the method collection valiable when a query has been started by calling dbname
        // * Certain methods are or are not avaliable once you have started a query such as insert -- you can only insert into root
        // ****************************************
        iAPI = TAFFY.mergeObj( TAFFY.mergeObj( API, { insert : undefined } ),
          { getDBI  : function () { return DBI; },
            getroot : function ( c ) { return root.call( c ); },
          context : function ( n ) {
            // ****************************************
            // *
            // * The context contains all the information to manage a query including filters, limits, and sorts
            // **************************************** 
            if ( n ){
              context = TAFFY.mergeObj( context,
                n.hasOwnProperty('results')
                  ? TAFFY.mergeObj( n, { run : new Date(), sort: new Date() })
                  : n
              );
            }
            return context;
          },
          extend  : undefined
        });

        context = (this && this.q) ? this : {
          limit     : false,
          start     : false,
          q         : [],
          filterRaw : [],
          index     : [],
          order     : [],
          results   : false,
          run       : null,
          sort      : null,
          settings  : settings
        };
        // ****************************************
        // *
        // * Call the query method to setup a new query
        // **************************************** 
        each( sortArgs(arguments), function ( f ) {

          if ( isIndexable( f ) ){
            context.index.push( f );
          }
          else {
            context.q.push( returnFilter( f ) );
          }
          context.filterRaw.push( f );
        });


        return iAPI;
      };

      // ****************************************
      // *
      // * If new records have been passed on creation of the DB either as JSON or as an array/object, insert them
      // **************************************** 
      TC++;
      if ( d ){
        DBI.insert( d );
      }


      root.insert = DBI.insert;

      root.merge = function ( i, key, runEvent ) {
        var
          search      = {},
          finalSearch = [],
          obj         = {}
          ;

        runEvent    = runEvent || false;
        key         = key      || 'id';

        each( i, function ( o ) {
          var existingObject;
          search[key] = o[key];
          finalSearch.push( o[key] );
          existingObject = root( search ).first();
          if ( existingObject ){
            DBI.update( existingObject.___id, o, runEvent );
          }
          else {
            DBI.insert( o, runEvent );
          }
        });

        obj[key] = finalSearch;
        return root( obj );
      };

      root.TAFFY = true;
      root.sort = DBI.sort;
      // ****************************************
      // *
      // * These are the methods that can be accessed on off the root DB function. Example dbname.insert;
      // **************************************** 
      root.settings = function ( n ) {
        // ****************************************
        // *
        // * Getting and setting for this DB's settings/events
        // **************************************** 
        if ( n ){
          settings = TAFFY.mergeObj( settings, n );
          if ( n.template ){

            root().update( n.template );
          }
        }
        return settings;
      };

      // ****************************************
      // *
      // * These are the methods that can be accessed on off the root DB function. Example dbname.insert;
      // **************************************** 
      root.store = function ( n ) {
        // ****************************************
        // *
        // * Setup localstorage for this DB on a given name
        // * Pull data into the DB as needed
        // **************************************** 
        var r = false, i;
        if ( localStorage ){
          if ( n ){
            i = localStorage.getItem( 'taffy_' + n );
            if ( i && i.length > 0 ){
              root.insert( i );
              r = true;
            }
            if ( TOb.length > 0 ){
              setTimeout( function () {
                localStorage.setItem( 'taffy_' + settings.storageName,
                  JSON.stringify( TOb ) );
              });
            }
          }
          root.settings( {storageName : n} );
        }
        return root;
      };

      // ****************************************
      // *
      // * Return root on DB creation and start having fun
      // **************************************** 
      return root;
    };
    // ****************************************
    // *
    // * Sets the global TAFFY object
    // **************************************** 
    TAFFY = T;


    // ****************************************
    // *
    // * Create public each method
    // *
    // ****************************************   
    T.each = each;

    // ****************************************
    // *
    // * Create public eachin method
    // *
    // ****************************************   
    T.eachin = eachin;
    // ****************************************
    // *
    // * Create public extend method
    // * Add a custom method to the API
    // *
    // ****************************************   
    T.extend = API.extend;


    // ****************************************
    // *
    // * Creates TAFFY.EXIT value that can be returned to stop an each loop
    // *
    // ****************************************  
    TAFFY.EXIT = 'TAFFYEXIT';

    // ****************************************
    // *
    // * Create public utility mergeObj method
    // * Return a new object where items from obj2
    // * have replaced or been added to the items in
    // * obj1
    // * Purpose: Used to combine objs
    // *
    // ****************************************   
    TAFFY.mergeObj = function ( ob1, ob2 ) {
      var c = {};
      eachin( ob1, function ( v, n ) { c[n] = ob1[n]; });
      eachin( ob2, function ( v, n ) { c[n] = ob2[n]; });
      return c;
    };


    // ****************************************
    // *
    // * Create public utility has method
    // * Returns true if a complex object, array
    // * or taffy collection contains the material
    // * provided in the second argument
    // * Purpose: Used to comare objects
    // *
    // ****************************************
    TAFFY.has = function ( var1, var2 ) {

      var re = false, n;

      if ( (var1.TAFFY) ){
        re = var1( var2 );
        if ( re.length > 0 ){
          return true;
        }
        else {
          return false;
        }
      }
      else {

        switch ( T.typeOf( var1 ) ){
          case 'object':
            if ( T.isObject( var2 ) ){
              eachin( var2, function ( v, n ) {
                if ( re === true && !T.isUndefined( var1[n] ) &&
                  var1.hasOwnProperty( n ) )
                {
                  re = T.has( var1[n], var2[n] );
                }
                else {
                  re = false;
                  return TAFFY.EXIT;
                }
              });
            }
            else if ( T.isArray( var2 ) ){
              each( var2, function ( v, n ) {
                re = T.has( var1, var2[n] );
                if ( re ){
                  return TAFFY.EXIT;
                }
              });
            }
            else if ( T.isString( var2 ) ){
              if ( !TAFFY.isUndefined( var1[var2] ) ){
                return true;
              }
              else {
                return false;
              }
            }
            return re;
          case 'array':
            if ( T.isObject( var2 ) ){
              each( var1, function ( v, i ) {
                re = T.has( var1[i], var2 );
                if ( re === true ){
                  return TAFFY.EXIT;
                }
              });
            }
            else if ( T.isArray( var2 ) ){
              each( var2, function ( v2, i2 ) {
                each( var1, function ( v1, i1 ) {
                  re = T.has( var1[i1], var2[i2] );
                  if ( re === true ){
                    return TAFFY.EXIT;
                  }
                });
                if ( re === true ){
                  return TAFFY.EXIT;
                }
              });
            }
            else if ( T.isString( var2 ) || T.isNumber( var2 ) ){
             re = false;
              for ( n = 0; n < var1.length; n++ ){
                re = T.has( var1[n], var2 );
                if ( re ){
                  return true;
                }
              }
            }
            return re;
          case 'string':
            if ( T.isString( var2 ) && var2 === var1 ){
              return true;
            }
            break;
          default:
            if ( T.typeOf( var1 ) === T.typeOf( var2 ) && var1 === var2 ){
              return true;
            }
            break;
        }
      }
      return false;
    };

    // ****************************************
    // *
    // * Create public utility hasAll method
    // * Returns true if a complex object, array
    // * or taffy collection contains the material
    // * provided in the call - for arrays it must
    // * contain all the material in each array item
    // * Purpose: Used to comare objects
    // *
    // ****************************************
    TAFFY.hasAll = function ( var1, var2 ) {

      var T = TAFFY, ar;
      if ( T.isArray( var2 ) ){
        ar = true;
        each( var2, function ( v ) {
          ar = T.has( var1, v );
          if ( ar === false ){
            return TAFFY.EXIT;
          }
        });
        return ar;
      }
      else {
        return T.has( var1, var2 );
      }
    };


    // ****************************************
    // *
    // * typeOf Fixed in JavaScript as public utility
    // *
    // ****************************************
    TAFFY.typeOf = function ( v ) {
      var s = typeof v;
      if ( s === 'object' ){
        if ( v ){
          if ( typeof v.length === 'number' &&
            !(v.propertyIsEnumerable( 'length' )) )
          {
            s = 'array';
          }
        }
        else {
          s = 'null';
        }
      }
      return s;
    };

    // ****************************************
    // *
    // * Create public utility getObjectKeys method
    // * Returns an array of an objects keys
    // * Purpose: Used to get the keys for an object
    // *
    // ****************************************   
    TAFFY.getObjectKeys = function ( ob ) {
      var kA = [];
      eachin( ob, function ( n, h ) {
        kA.push( h );
      });
      kA.sort();
      return kA;
    };

    // ****************************************
    // *
    // * Create public utility isSameArray
    // * Returns an array of an objects keys
    // * Purpose: Used to get the keys for an object
    // *
    // ****************************************   
    TAFFY.isSameArray = function ( ar1, ar2 ) {
      return (TAFFY.isArray( ar1 ) && TAFFY.isArray( ar2 ) &&
        ar1.join( ',' ) === ar2.join( ',' )) ? true : false;
    };

    // ****************************************
    // *
    // * Create public utility isSameObject method
    // * Returns true if objects contain the same
    // * material or false if they do not
    // * Purpose: Used to comare objects
    // *
    // ****************************************   
    TAFFY.isSameObject = function ( ob1, ob2 ) {
      var T = TAFFY, rv = true;

      if ( T.isObject( ob1 ) && T.isObject( ob2 ) ){
        if ( T.isSameArray( T.getObjectKeys( ob1 ),
          T.getObjectKeys( ob2 ) ) )
        {
          eachin( ob1, function ( v, n ) {
            if ( ! ( (T.isObject( ob1[n] ) && T.isObject( ob2[n] ) &&
              T.isSameObject( ob1[n], ob2[n] )) ||
              (T.isArray( ob1[n] ) && T.isArray( ob2[n] ) &&
                T.isSameArray( ob1[n], ob2[n] )) || (ob1[n] === ob2[n]) )
            ) {
              rv = false;
              return TAFFY.EXIT;
            }
          });
        }
        else {
          rv = false;
        }
      }
      else {
        rv = false;
      }
      return rv;
    };

    // ****************************************
    // *
    // * Create public utility is[DataType] methods
    // * Return true if obj is datatype, false otherwise
    // * Purpose: Used to determine if arguments are of certain data type
    // *
    // * mmikowski 2012-08-06 refactored to make much less "magical":
    // *   fewer closures and passes jslint
    // *
    // ****************************************

    typeList = [
      'String',  'Number', 'Object',   'Array',
      'Boolean', 'Null',   'Function', 'Undefined'
    ];
  
    makeTest = function ( thisKey ) {
      return function ( data ) {
        return TAFFY.typeOf( data ) === thisKey.toLowerCase() ? true : false;
      };
    };
  
    for ( idx = 0; idx < typeList.length; idx++ ){
      typeKey = typeList[idx];
      TAFFY['is' + typeKey] = makeTest( typeKey );
    }
  }
}());

if ( typeof(exports) === 'object' ){
  exports.taffy = TAFFY;
}

},{}],25:[function(require,module,exports){
function normalize (str) {
  return str
          .replace(/[\/]+/g, '/')
          .replace(/\/\?/g, '?')
          .replace(/\/\#/g, '#')
          .replace(/\:\//g, '://');
}

module.exports = function () {
  var joined = [].slice.call(arguments, 0).join('/');
  return normalize(joined);
};
},{}]},{},[4])(4)
});

var DefaultConfig = {
  marketId: 'core'
};

var app = new MDP.Application(null, $.extend({}, DefaultConfig, MDPConfig));

// Temporary hacky module availability
window.Modules = app.modules;

// Temporary fix to wire register functions
window.registerService = app.registerService;
window.registerHelper = app.registerHelper;
window.registerModule = app.registerModule;
window.registerTemplate = function(name, service) {
  app.services('templateService').register(name, service);
};

$(function() {
  app.setContext(document.body);
});

Handlebars.registerHelper('compare', function (lvalue, operator, rvalue, options) {

    var operators, result;
    
    if (arguments.length < 3) {
        throw new Error("Handlerbars Helper 'compare' needs 2 parameters");
    }
    
    if (options === undefined) {
        options = rvalue;
        rvalue = operator;
        operator = "===";
    }
    
    operators = {
        '==': function (l, r) { return l == r; },
        '===': function (l, r) { return l === r; },
        '!=': function (l, r) { return l != r; },
        '!==': function (l, r) { return l !== r; },
        '<': function (l, r) { return l < r; },
        '>': function (l, r) { return l > r; },
        '<=': function (l, r) { return l <= r; },
        '>=': function (l, r) { return l >= r; },
        '&&': function (l, r) { return l && r; },
        '||': function (l, r) { return l || r; },
        'typeof': function (l, r) { return typeof l == r; }
    };
    
    if (!operators[operator]) {
        throw new Error("Handlerbars Helper 'compare' doesn't know the operator " + operator);
    }
    
    result = operators[operator](lvalue, rvalue);
    
    if (result) {
        return options.fn(this);
    } else {
        return options.inverse(this);
    }

});

// a grouped 'each' loop.
// usage: {{#grouped_each 5 array}} : each 5 items
Handlebars.registerHelper('grouped_each', function(every, context, options) {
    var output = "",
        subcontext = [];
    if (context && !!context.length) {
        for (var i = 0; i < context.length; i++) {
            if (i > 0 && i % every === 0) {
                output += options.fn(subcontext);
                subcontext = [];
            }
            subcontext.push(context[i]);
        }
        output += options.fn(subcontext);
    }
    return output;
});

Handlebars.registerHelper('if_even', function(conditional, options) {
    if((conditional % 2) == 0) {
        return options.fn(this);
    } else {
        return options.inverse(this);
    }
});

// a limited 'each' loop.
// usage: {{#limited_each array limit="10"}} : items 0 thru 9
// limit defaults to array length
Handlebars.registerHelper('limited_each', function(context, options) {
    var output = "",
        limit = parseInt(options.hash.limit) || context.length,
        length = (limit < context.length) ? limit : context.length;

    for (i = 0; i < length; i++) {
        output += options.fn(context[i]);
    }
 
  return output;
});

// basic maths helpers
// usage: {{math @index "+" 1}}
Handlebars.registerHelper("math", function(lvalue, operator, rvalue) {
    lvalue = parseFloat(lvalue);
    rvalue = parseFloat(rvalue);

    return {
        "+": lvalue + rvalue,
        "-": lvalue - rvalue,
        "*": lvalue * rvalue,
        "/": lvalue / rvalue,
        "%": lvalue % rvalue
    }[operator];
});

// Replace occurrences of string "A" with string "B"
// usage: {{replace "my string" "%" "value"}}
Handlebars.registerHelper("replace", function(string, a, b) {
    if(string && typeof string === "string") {
        return string.split(a).join(b);
    }
});

Handlebars.registerHelper('ternary', function (value, substitute) {
    if (!value) {
        value = substitute;
    }

    return new Handlebars.SafeString(value);
});


Handlebars.registerHelper('wrapAtWord', function (value, index) {

    var str = value;
    var word = str.split(' ')[index];
    var el = '<span>' + word + '</span>';

    str = str.replace(word, el);

    return str;

});
/**!![helper.accordion]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_accordion-item"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<li accordion-item>\n    <div accordion-item-thumb>"
    + escapeExpression(lambda((depth0 != null ? depth0.thumb : depth0), depth0))
    + "</div>\n    <div accordion-item-content>"
    + escapeExpression(lambda((depth0 != null ? depth0.content : depth0), depth0))
    + "</div>\n</li>";
},"useData":true});
this["templates"]["_accordion"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  return "<ul accordion>\n\n</ul>";
  },"useData":true});
this["templates"]["_content-b"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  return "Content C";
  },"useData":true});
this["templates"]["_thumb-a"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  return "Title A";
  },"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.accordion.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("accordion", function(application) {
var Accordion = (function(){
    var Services = new app.services()
    ,   selectors = {
            accordion: "[accordion]",
            accordionItem: "[accordion-item]",
            accordionItemThumb: "[accordion-item-thumb]",
            accordionItemContent: "[accordion-item-content]"
        };

    var setElements = function(){
        if (!this.items) return setInterpolation.call(this);
        this.$accordion = $(this.templates.accordion()).closest(this.selectors.accordion);
        this.items.forEach(function(item){
            setItem.call(this,item);
        }.bind(this));
        this.binded = true;
        this.$container.html(this.$accordion);
    }

    var setInterpolation = function(){
        this.items = [];
        this.$accordion = this.$container.find(this.selectors.accordion).first();
        this.$accordion.find(this.selectors.accordionItem).first().parent().children(this.selectors.accordionItem).each(function(i,element){
            var $element = $(element);
            var item = {
                index: i,
                selected: this.isSelected($element)
            }
            this.items.push(item);
            setItem.call(this,item,$element);
        }.bind(this));
        this.binded = true;
        this.interpolated = true;

        this.events.onComplete.call(this, this.items);
    };

    var setItem = function(item,$element) {
        $.extend(item, {
            $element: $element || $(this.templates.accordionItem(item)),
            selected: item.selected === "true"
        });
        if (!$element) this.$accordion.append(item.$element);
        bindItemEvents.call(this, item);
        setItemSelection.call(this,item,item.selected);

        var $container = item.$element.find(".helper-accordion.level-2 > li");
        this.events.onLoad.call(this, item, $container);
    };

    var setItemSelection = function(item,selected) {
        //FIXME: Multi items missing
        item.selected = selected!=undefined ? selected : !item.selected;
        this.selection.call(this,item.$element,item.selected);

        var $container = item.$element.find(".helper-accordion.level-2 > li");
        if (item.selected) {
            this.events.onOpen.call(this, item, $container);
        } else {
            this.events.onClose.call(this, item, $container);
        }
    };

    var makeSelection = function(status){
        this[status ? "addClass" : "removeClass"]("selected");
    }

    var isSelected = function($element){
        var selected = $element.data("selected");
        return selected ? (selected).toString().toLowerCase() : selected;
    }

    var toggleItem = function(currentItem){
        setItemSelection.call(this,currentItem);
        if (!this.multi) {
            this.items.forEach(function(item) {
                if (item.$element[0]!=currentItem.$element[0]) setItemSelection.call(this,item,false);
            }.bind(this));
        }

        var $container = currentItem.$element.find(".helper-accordion.level-2 > li");
        this.events.onToggleComplete.call(this, currentItem, $container);
    };

    var bindItemEvents = function(item){
        if (!item.$element.find(this.selectors.accordionItemContent).length) return false;
        var _handler = function(e){
            e.preventDefault();
            return toggleItem.bind(this,item)();
        }.bind(this);
        item.$element.find(this.selectors.accordionItemThumb).first().off("click.accordion",_handler).on("click.accordion",_handler);
    };

    var unbindItemEvents = function(item){
        if (!item.$element.find(this.selectors.accordionItemContent).length) return false;
        item.$element.find(this.selectors.accordionItemThumb).first().off("click.accordion");
    };

    // Constructor
    var Accordion = function(config){
        $.extend(this,
            $.extend(true,{
                $container: undefined,
                items: undefined,
                templates: {
                    accordion: Services.templateService.templates("helper._accordion"),
                    accordionItem: Services.templateService.templates("helper._accordion-item")
                },
                multi: false,
                events: {
                    onLoad: function () {},
                    onClose: function () {},
                    onOpen: function () {},
					onToggleComplete: function () {},
					onComplete: function () {}
                },
                selectors: $.extend({},selectors),
                selection: makeSelection,
                isSelected: isSelected
            },config)
        );

        // Init
        setElements.call(this);
    };

    Accordion.prototype.toggle = function(item){
        toggleItem.call(this,item);
    }

    Accordion.prototype.toggleByIndex = function (index) {
        toggleItem.call(this, this.items[index]);
    }

    Accordion.prototype.bindEvents = function(){
        if(this.binded) return;
        this.items.forEach(function(item){
            bindItemEvents.call(this,item);
        }.bind(this));
        this.binded = true;
    };

    Accordion.prototype.unbindEvents = function(){
        if(!this.binded) return;
        this.items.forEach(function(item){
            unbindItemEvents.call(this,item);
        }.bind(this));
        this.binded = false;
    };

    Accordion.prototype.destroy = function(){
        if(this.interpolated) this.unbindEvents();
        else this.$accordion.remove();
    };

    return Accordion;
})();

return Accordion;
});
}).apply(window);/**!!<[helper.accordion]!!**/
/**!![helper.appointment-booking]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_bookingDate"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<h3 class=\"title mobile-hide\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingdate : stack1)) != null ? stack1.label : stack1), depth0))
    + "</h3>\n<h3 class=\"title desktop-hide\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.heading : stack1), depth0))
    + "</h3>\n<div class=\"field-row\">\n    <div class=\"field\" data-validation=\"single\">\n        <div class=\"field-input error-underline\">\n            <input class=\"hide-desktop\" type=\"datetime-local\" name=\"service-datetime\" value=\"\"/>\n            <input type=\"date\" name=\"service-date\" value=\"\" data-validation-id=\"service-date\" data-validation-matchers=\"[Validation.matchers.isNotEmpty]\"/>\n            <div class=\"date-picker hide-mobile\"></div>\n        </div>\n\n        <div class=\"validation-container\">\n            <div class=\"validation\" data-validation-message=\"service-date\" data-validation-match=\"0\">\n                "
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingdate : stack1)) != null ? stack1.validation : stack1)) != null ? stack1.required : stack1), depth0))
    + "\n            </div>\n        </div>\n    </div>\n</div>";
},"useData":true});
this["templates"]["_bookingSummary"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<h3 class=\"title\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingsummary : stack1)) != null ? stack1.label : stack1)) != null ? stack1.title : stack1), depth0))
    + "</h3>\n\n<div class=\"clearfix\">\n	<div class=\"date\">\n		<p>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingsummary : stack1)) != null ? stack1.label : stack1)) != null ? stack1.date : stack1), depth0))
    + ": <span>"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Data : depth0)) != null ? stack1.humanDate : stack1), depth0))
    + "</span></p>\n	</div>\n	<div class=\"time\">\n		<p>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingsummary : stack1)) != null ? stack1.label : stack1)) != null ? stack1.time : stack1), depth0))
    + ": <span>"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Data : depth0)) != null ? stack1.formattedTime : stack1), depth0))
    + "</span></p>\n	</div>\n</div>";
},"useData":true});
this["templates"]["_bookingTime"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<h3 class=\"title\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingtime : stack1)) != null ? stack1.label : stack1)) != null ? stack1.title : stack1), depth0))
    + "</h3>\n\n<div class=\"field-row\">\n\n    <div class=\"field\" data-validation=\"single\">\n        <div class=\"field-input preferred-appointment hide-mobile\">\n\n            <input class=\"mdp-radio\" type=\"radio\" name=\"time-frame\" value=\"am\" id=\"preffered-time-am\" checked=\"checked\" data-validation-id=\"time\">\n			<label for=\"preffered-time-am\"></label>\n            <label for=\"preffered-time-am\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingtime : stack1)) != null ? stack1.label : stack1)) != null ? stack1.am : stack1), depth0))
    + "</label>\n\n        </div>\n        <div class=\"field-input preferred-appointment hide-mobile\">\n\n            <input class=\"mdp-radio\" type=\"radio\" name=\"time-frame\" value=\"pm\" id=\"preffered-time-pm\" data-validation-id=\"time\">\n			<label for=\"preffered-time-pm\"></label>\n            <label for=\"preffered-time-pm\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingtime : stack1)) != null ? stack1.label : stack1)) != null ? stack1.pm : stack1), depth0))
    + "</label>\n\n        </div>\n\n		<div class=\"field-input error-underline\">\n\n            <input type=\"time\" value=\"\" name=\"service-time\" step=\"900\" min=\"\" max=\"\" data-validation-id=\"service-time\" data-validation-matchers=\"[Validation.matchers.isNotEmpty]\"/>\n\n            <div class=\"time-block clearfix hide-mobile\">\n                <div class=\"res-1024-cols-6\">\n\n                    <label>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingtime : stack1)) != null ? stack1.label : stack1)) != null ? stack1.hour : stack1), depth0))
    + ":</label>\n\n                    <div class=\"time-picker-hours\">\n                        <table class=\"time-hour\" data-time-section=\"am\">\n                            <tr>\n                                <td data-time-value=\"00\">00</td>\n                                <td data-time-value=\"01\">01</td>\n                                <td data-time-value=\"02\">02</td>\n                                <td data-time-value=\"03\">03</td>\n                            </tr>\n							<tr>\n								<td data-time-value=\"04\">04</td>\n								<td data-time-value=\"05\">05</td>\n								<td data-time-value=\"06\">06</td>\n								<td data-time-value=\"07\">07</td>\n                        	</tr>\n							<tr>\n								<td data-time-value=\"08\">08</td>\n								<td data-time-value=\"09\">09</td>\n								<td data-time-value=\"10\">10</td>\n								<td data-time-value=\"11\">11</td>\n                        	</tr>\n                        </table>\n                        <table class=\"time-hour hidden\" data-time-section=\"pm\">\n                            <tr>\n                                <td data-time-value=\"12\">12</td>\n                                <td data-time-value=\"13\">1</td>\n                                <td data-time-value=\"14\">2</td>\n                                <td data-time-value=\"15\">3</td>\n                            </tr>\n							<tr>\n								<td data-time-value=\"16\">4</td>\n								<td data-time-value=\"17\">5</td>\n								<td data-time-value=\"18\">6</td>\n								<td data-time-value=\"19\">7</td>\n                       		</tr>\n							<tr>\n								<td data-time-value=\"20\">8</td>\n								<td data-time-value=\"21\">9</td>\n								<td data-time-value=\"22\">10</td>\n								<td data-time-value=\"23\">11</td>\n                        	</tr>\n                        </table>\n                    </div>\n                </div>\n                <div class=\"res-1024-cols-6\">\n                    <label>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingtime : stack1)) != null ? stack1.label : stack1)) != null ? stack1.minute : stack1), depth0))
    + ":</label>\n\n                    <div class=\"time-picker-minutes\">\n                        <table class=\"time-minute\">\n                            <tr>\n                                <td data-time-value=\"00\">00</td>\n                                <td data-time-value=\"15\">15</td>\n                                <td data-time-value=\"30\">30</td>\n                                <td data-time-value=\"45\">45</td>\n                            </tr>\n                        </table>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"validation-container\">\n            <div class=\"validation\" data-validation-message=\"service-time\" data-validation-match=\"0\">\n				"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.bookingtime : stack1)) != null ? stack1.validation : stack1)) != null ? stack1.required : stack1), depth0))
    + "\n            </div>\n        </div>\n    </div>\n\n</div>";
},"useData":true});
this["templates"]["_dealerDetails"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "            <tr>\n                <th>"
    + escapeExpression(lambda((depth0 != null ? depth0.Day : depth0), depth0))
    + "</th>\n                <td>\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.SingleOpenCloseTime : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.program(4, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                </td>\n            </tr>\n";
},"2":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        "
    + escapeExpression(lambda((depth0 != null ? depth0.OpenTime : depth0), depth0))
    + "\n";
},"4":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        "
    + escapeExpression(lambda((depth0 != null ? depth0.FormattedOpenTime : depth0), depth0))
    + " - "
    + escapeExpression(lambda((depth0 != null ? depth0.FormattedCloseTime : depth0), depth0))
    + "\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "<h3 class=\"title\">"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Data : depth0)) != null ? stack1.DealerName : stack1), depth0))
    + "</h3>\n\n<div class=\"chosen-dealer-times\">\n    <label>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Language : depth0)) != null ? stack1.appointmentstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.dealerdetails : stack1)) != null ? stack1.label : stack1), depth0))
    + ":</label>\n    <table>\n";
  stack1 = helpers.each.call(depth0, ((stack1 = ((stack1 = (depth0 != null ? depth0.Data : depth0)) != null ? stack1.OpeningTimes : stack1)) != null ? stack1.Days : stack1), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "    </table>\n</div>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.appointment-booking.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("appointment-booking", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var AppointmentBooking = function() {
    "use strict";

    function AppointmentBooking(config) {
        this.Services = new app.services();
        this.Helpers = new app.helpers();

        var defaultConfig = {
			scope: null,
			templates: {
				_bookingSummary: this.Services.templateService.templates("helper.appointment-booking._bookingSummary"),
				_bookingDate: this.Services.templateService.templates("helper.appointment-booking._bookingDate"),
				_bookingTime: this.Services.templateService.templates("helper.appointment-booking._bookingTime"),
				_dealerDetails: this.Services.templateService.templates("helper.appointment-booking._dealerDetails")
			},
			language: {},
			department: "Service" // Possible values: Service, Sales, Parts
		};
        this.config = $.extend({}, defaultConfig, config);

        this.$scope = this.config.scope;
        this.Templates = this.config.templates;

        this.booking={
			"chosenDate": null,
			"chosenTime": null,
			"formattedTime": null
		};

        this.dealerData=null;
        this.timePicker={
			"chosenHour": null,
			"chosenMinute": null
		};
        this.datePicker=null;

        // Date time utility
        this.dateTimeUtility = new (this.Helpers["date-time"])({});

        this.dateTimeFormats = {
			"TwelveHour": "h:mm a",
			"PrettyDate": "dddd MMMM Do YYYY",
			"PrettyDateFr": "dddd Do MMMM YYYY"

		};

        this.animated = true;
        this.speedFocus = 800;

        this.init();
    }

    $__Object$defineProperties(AppointmentBooking.prototype, {
        init: {
            value: function() {
                // Create standard date and Time picker
                this.createTimePicker();
                this.createDatePicker();
                this.bindDatePicker();
                this.bindDateTimePicker();
            },

            enumerable: false,
            writable: true
        },

        setDealer: {
            value: function(dealerData) {
                this.booking={
                    "chosenDate": null,
                    "chosenTime": null,
                    "formattedTime": null
                };

                this.timePicker={
                    "chosenHour": null,
                    "chosenMinute": null
                };

                this.dealerData = JSON.parse(JSON.stringify(dealerData));

                this.setChosenDealerDetails();

                var chosenDays = this.setDealerAvailableDaysTimes();
                this.resetDatePicker(chosenDays);

                this.resetTimePicker();
                this.setTimePickerAvailableHours( false );
            },

            enumerable: false,
            writable: true
        },

        padTwoDigits: {
            value: function(d) {
                d=parseInt(d);
                return (d < 10) ? "0" + d.toString() : d.toString();
            },

            enumerable: false,
            writable: true
        },

        formatDate: {
            value: function(date) {
                return date.getFullYear()+"-"+this.padTwoDigits(date.getMonth() + 1)+"-"+this.padTwoDigits(date.getDate());
            },

            enumerable: false,
            writable: true
        },

        setTimeField: {
            value: function() {
                if(this.timePicker.chosenHour !== null && this.timePicker.chosenMinute !== null) {
                    var timeField = this.$scope.find("input[name=\"service-time\"]"),
                        time = this.dateTimeUtility.padTime( this.timePicker.chosenHour+":"+this.timePicker.chosenMinute );

                    timeField.val(time);
                    timeField.trigger("change");

                    this.setDateTimeField();
                }
            },

            enumerable: false,
            writable: true
        },

        setDateField: {
            value: function(date) {
                var dateField = this.$scope.find("input[name=\"service-date\"]");

                $(dateField).val(this.formatDate(date));
                dateField.trigger("change");

                this.setDateTimeField();
            },

            enumerable: false,
            writable: true
        },

        setDateTimeField: {
            value: function() {
                var $timeField = this.$scope.find("input[name=\"service-time\"]"),
                    $dateField = this.$scope.find("input[name=\"service-date\"]"),
                    $dateTimeField = this.$scope.find("input[name=\"service-datetime\"]"),
                    time = (!$timeField.val()) ? "00:00" : $timeField.val();

                $dateTimeField.val($dateField.val()+"T"+time);
            },

            enumerable: false,
            writable: true
        },

        bindDateTimePicker: {
            value: function() {
                var dateTimeField = this.$scope.find("input[name=\"service-datetime\"]"),
                    submitButton = this.$scope.find(".step-submit-button");

                dateTimeField.val("");

                dateTimeField.on("change", function(e) {
                    var chosenDateTime = $(e.target).val().split("T"),
                        $timeField = this.$scope.find("input[name=\"service-time\"]"),
                        $dateField = this.$scope.find("input[name=\"service-date\"]");

                    submitButton.removeClass("complete");

                    this.booking.chosenDate = chosenDateTime[0];
                    this.booking.chosenTime = chosenDateTime[1];
                    this.booking.formattedTime = this.formatToTwelveHour(chosenDateTime[1]);

                    if($dateField.val() !== "") {
                        this.booking.chosenDate = new Date(chosenDateTime[0]);
                        this.booking.chosenDateNonObject = chosenDateTime[0];
                    }

                    $dateField.val(chosenDateTime[0]);
                    $timeField.val(chosenDateTime[1]);

                    this.generateBookingSummary();
                }.bind(this));

                dateTimeField.on("focus", function(e) {
                    this.booking={
                        "chosenDate": null,
                        "chosenTime": null,
                        "formattedTime": null
                    };

                    dateTimeField.val("");
                    submitButton.removeClass("complete");

                    //chosen-dealer-details
                    this.focusOnOpeningTimes();
                    this.generateBookingSummary();
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        focusOnOpeningTimes: {
            value: function() {
                this.$scope.find(".booking-date").velocity("scroll", {
                    duration: this.speedFocus,
                    easing: "easeInOutQuint",
                    complete: function() {}
                });
            },

            enumerable: false,
            writable: true
        },

        createTimePicker: {
            value: function() {
                this.$scope.find("[data-page-section=\"booking-time\"]").empty();
                this.$scope.find("[data-page-section=\"booking-time\"]").append(
                    this.Templates._bookingTime( { "Data": {}, "Language": this.config.language } )
                );
                //if fr, use 24h as data-picker labels
                if(this.dateTimeUtility.language.toLowerCase() === "fr-ca"){
                    var timeTable = this.$scope.find(".time-hour td");
                    $(timeTable).each(function(index, value){
                        if (index > 11){
                            var pmHours = $(this).html() + " PM",                 
                            momentObj = moment(pmHours, ["h:mm A"]).format("HH");
                            $(this).html(momentObj);
                        }
                    });
                }
                this.bindTimePicker();
            },

            enumerable: false,
            writable: true
        },

        bindTimePicker: {
            value: function() {
                var timeField = this.$scope.find("input[name=\"service-time\"]"),
                    timeFrameField = this.$scope.find("input[name=\"time-frame\"]");

                timeField.val("");

                // Time Picker - 12 hour AM / PM toggle
                var hourBlocks = this.$scope.find(".time-hour"),
                    submitButton = this.$scope.find(".step-submit-button");

                timeFrameField.on("change", function(e) {
                    var timeFrame = $(e.target).val();

                    hourBlocks.addClass("hidden");
                    this.$scope.find("[data-time-section=\""+ timeFrame +"\"]").removeClass("hidden");

                    submitButton.removeClass("complete");
                }.bind(this));

                // Time picker - Hour
                var hourItems = this.$scope.find(".time-hour td");
                hourItems.on("click", function(e) {
                    var hourItem = $(e.target);

                    if(! hourItem.hasClass("disabled")) {
                        hourItems.removeClass("selected");
                        hourItem.addClass("selected");

                        submitButton.removeClass("complete");

                        this.timePicker.chosenHour = hourItem.attr("data-time-value");
                        this.setTimePickerAvailableMinutes(this.timePicker.chosenHour);

                        this.setTimeField();
                    }
                }.bind(this));

                // Time picker - Minute
                var minuteItems = this.$scope.find(".time-minute td");
                minuteItems.on("click", function(e) {
                    var minuteItem = $(e.target);

                    if(! minuteItem.hasClass("disabled")) {
                        minuteItems.removeClass("selected");
                        minuteItem.addClass("selected");

                        submitButton.removeClass("complete");

                        this.timePicker.chosenMinute = minuteItem.attr("data-time-value");
                        this.setTimeField();
                    }
                }.bind(this));

                timeField.on("change", function(e) {
                    submitButton.removeClass("complete");

                    this.booking.chosenTime = $(e.target).val();
                    this.booking.formattedTime = this.formatToTwelveHour(this.booking.chosenTime);

                    this.generateBookingSummary();
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        setTimePickerAvailableHours: {
            value: function(openingTimes) {
                var amContainer = this.$scope.find("[data-time-section=\"am\"]"),
                    pmContainer = this.$scope.find("[data-time-section=\"pm\"]");

                amContainer.find("[data-time-value]").removeClass("disabled");
                pmContainer.find("[data-time-value]").removeClass("disabled");

                if(typeof openingTimes !== "undefined" && openingTimes) {
                    // Hour list
                    var twelveHour = {
                        "am": ["00","01","02","03","04","05","06","07","08","09","10","11"],
                        "pm": ["12","13","14","15","16","17","18","19","20","21","22","23"]
                    };

                    var openTime = openingTimes.from.split(":"),
                        closeTime = openingTimes.to.split(":");

                    // AM
                    twelveHour.am.forEach( function(current, key)
                    {
                        var currentDay = amContainer.find("[data-time-value=\""+ current +"\"]");

                        if(openTime[0] > current) {
                            currentDay.addClass("disabled");
                        } else if(openTime[0] < current && closeTime[0] < current) {
                            currentDay.addClass("disabled");
                        }
                    });

                    // PM
                    twelveHour.pm.forEach( function(current, key)
                    {
                        var currentDay = pmContainer.find("[data-time-value=\""+ current +"\"]");

                        if(openTime[0] > current) {
                            currentDay.addClass("disabled");
                        } else if((openTime[0] < current && closeTime[0] < current) || (closeTime[1] == "00" && closeTime[0] == current)) {
                            currentDay.addClass("disabled");
                        }
                    });
                }
            },

            enumerable: false,
            writable: true
        },

        setTimePickerAvailableMinutes: {
            value: function(currentHour) {
                var dealerTimes = this.dealerOpeningTimes[this.booking.chosenDate.getDay()];

                var minuteContainer = this.$scope.find(".time-minute");
                minuteContainer.find("[data-time-value]").removeClass("disabled");

                var openTime = dealerTimes.opening.split(":"),
                    closeTime = dealerTimes.closing.split(":");

                function loopMinuteEntities(type, timeValue) {
                    var minutes = ["00","15","30","45"];

                    minutes.forEach(function(current, key) {
                        var currentMinute = minuteContainer.find("[data-time-value=\""+ current +"\"]");

                        switch(type) {
                            case "open":
                                if (timeValue[1] > current) {
                                    currentMinute.addClass("disabled");
                                }
                            break;
                            default:
                                if (timeValue[1] <= current) {
                                    currentMinute.addClass("disabled");
                                }
                            break;
                        }
                    });
                }

                if (currentHour == openTime[0]) {
                    loopMinuteEntities("open", openTime);
                } else if (currentHour == closeTime[0]) {
                    loopMinuteEntities("closed", closeTime);
                }
            },

            enumerable: false,
            writable: true
        },

        createDatePicker: {
            value: function() {
                this.$scope.find("[data-page-section=\"booking-date\"]").append(
                    this.Templates._bookingDate( { "Data": {}, "Language": this.config.language } )
                );

                var container = this.$scope.find("div.date-picker");

                this.datePicker = new (this.Helpers["date-picker"])({
                    scope: container,
                    pickerConfig: {
                        weekStart: 1, // Start the week on Monday
                        //format: 'yyyy-MM-dd',
                        startDate: "+0d" // Disable past dates
                    }
                });
            },

            enumerable: false,
            writable: true
        },

        resetDatePicker: {
            value: function(daysClosed) {
                var dateField = this.$scope.find("input[name=\"service-date\"]"),
                    desktopTimeField = this.$scope.find(".time-block");

                dateField.val("");
                dateField.attr("min", this.formatDate( new Date() ) );
                dateField.trigger("change");

                desktopTimeField.find("td").removeClass("selected");

                if(this.datePicker !== null)
                    this.datePicker.destroy();

                var container = this.$scope.find("div.date-picker");

                this.datePicker = new (this.Helpers["date-picker"])({
                    scope: container,
                    pickerConfig: {
                        weekStart: 1, // Start the week on Monday
                        //format: 'yyyy-MM-dd',
                        startDate: "+0d", // Disable past dates
                        daysOfWeekDisabled: daysClosed
                    }
                });
            },

            enumerable: false,
            writable: true
        },

        resetTimePicker: {
            value: function() {
                this.createTimePicker();
            },

            enumerable: false,
            writable: true
        },

        bindDatePicker: {
            value: function() {
                var dateField = this.$scope.find("input[name=\"service-date\"]");
                dateField.attr("min", this.formatDate( new Date() ) );

                this.datePicker.picker.on("changeDate", function(e){
                    this.setDateField(e.date);
                }.bind(this));

                dateField.on("change", function(e) {
                    var timeField = this.$scope.find("input[name=\"service-time\"]"),
                        selectedDate = $(e.target).val(),
                        desktopTimeField = this.$scope.find(".time-block"),
                        submitButton = this.$scope.find(".step-submit-button");

                    submitButton.removeClass("complete");

                    if(selectedDate !== "") {
                        this.booking.chosenDate = new Date( selectedDate );
                        this.booking.chosenDateNonObject = selectedDate;
                    }

                    if(this.booking.chosenDate !== null
                        && typeof this.dealerOpeningTimes !== "undefined"
                        && typeof this.dealerOpeningTimes[this.booking.chosenDate.getDay()] !== "undefined") {
                        var dealerTimes = this.dealerOpeningTimes[this.booking.chosenDate.getDay()];

                        this.booking.humanDate = null;
                        this.booking.chosenTime = null;
                        this.booking.formattedTime = null;

                        this.timePicker={
                            "chosenHour": null,
                            "chosenMinute": null
                        };

                        timeField.val("");
                        timeField.attr("min", dealerTimes.opening);
                        timeField.attr("max", dealerTimes.closing);

                        desktopTimeField.find("td").removeClass("selected");

                        this.setTimePickerAvailableHours({
                            "from": dealerTimes.opening,
                            "to": dealerTimes.closing
                        });
                    }

                    this.generateBookingSummary();
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        formatToTwelveHour: {
            value: function(time) {
                return this.dateTimeUtility.formatDate(
                    "1970-01-01 " + this.dateTimeUtility.padTime(time),
                    this.dateTimeFormats.TwelveHour
                );
            },

            enumerable: false,
            writable: true
        },

        formatToFrench: {
            value: function(time) {
                return moment(time, ["h:mm A"]).format("HH:mm").replace(":", " h ").replace("00", "").replace(/^(0)/, "");
            },

            enumerable: false,
            writable: true
        },

        setChosenDealerDetails: {
            value: function() {
                var dataSpoof = {
                    DealerName: this.dealerData.Dealer.DealerName,
                    OpeningTimes: {
                        Days: []
                    }
                }

                // Temporary pre-go-live fix
                var toFrench = this.dateTimeUtility.language.toLowerCase() === "fr-ca",
                    map = {
                        "Sunday": "Dimanche",
                        "Monday": "Lundi",
                        "Tuesday": "Mardi",
                        "Wednesday": "Mercredi",
                        "Thursday": "Jeudi",
                        "Friday": "Vendredi",
                        "Saturday": "Samedi",
                        "Sales": "Ventes",
                        "Service": "Service",
                        "Parts": "Pièces",
                        "Closed": "Fermé"
                    };
                // Temporary pre-go-live fix

                if(this.dealerData !== null) {
                    this.dealerData.Dealer.OpeningTimes.forEach(function(department, departmentIndex) {
                        if(department.ServiceType === this.config.department){
                            department.Days.forEach(function(dayDetails, dayIndex) {
                                var day = toFrench ? map[dayDetails.Day] : dayDetails.Day,
                                    openTime = toFrench ? map[dayDetails.OpenTime] : dayDetails.OpenTime,
                                    closeTime = toFrench ? map[dayDetails.CloseTime] : dayDetails.CloseTime,
                                    formattedOpenTime = typeof openTime === "string" && openTime.split(":").length <= 1 ? openTime : this.formatToTwelveHour(dayDetails.OpenTime),
                                    formattedCloseTime = typeof closeTime === "string" && closeTime.split(":").length <= 1 ? closeTime : this.formatToTwelveHour(dayDetails.CloseTime);

                                dataSpoof.OpeningTimes.Days.push({
                                    Day: day,
                                    OpenTime: openTime,
                                    CloseTime: closeTime,
                                    FormattedOpenTime: formattedOpenTime,
                                    FormattedCloseTime: formattedCloseTime,
                                    SingleOpenCloseTime: typeof openTime === "string" && openTime.split(":").length <= 1
                                });
                            }.bind(this));
                        }
                    }.bind(this));
                }

                this.$scope.find("[data-page-section=\"chosen-dealer-details\"]").empty();
                var self = this;
                //if fr replace dealers opening times summary
                if(this.dateTimeUtility.language.toLowerCase() === "fr-ca"){
                    var timesArray = dataSpoof.OpeningTimes.Days;
                    $.map(timesArray, function(val, i) {
                        timesArray[i].FormattedCloseTime = self.formatToFrench(timesArray[i].FormattedCloseTime);
                        timesArray[i].FormattedOpenTime = self.formatToFrench(timesArray[i].FormattedOpenTime);
                    });
                    dataSpoof.OpeningTimes.Days = timesArray;
                }

                this.$scope.find("[data-page-section=\"chosen-dealer-details\"]").append(
                    this.Templates._dealerDetails( { "Data": dataSpoof, "Language": this.config.language } )
                );
            },

            enumerable: false,
            writable: true
        },

        setDealerAvailableDaysTimes: {
            value: function() {
                // Start of Date and time booking

                // FYI: The keyedDays here are very important, they match the keys used on the Server Side to allow us to match a week day in any language, they are a text based ID
                // The days closed are a key to the days of the week where by browser standards have Sunday as the week start day
                this.dealerOpeningTimes = [];
                var keyedDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
                    daysClosed=[];

                if(this.dealerData !== null) {
                    this.dealerData.Dealer.OpeningTimes.forEach(function(department, departmentIndex) {
                        if(department.ServiceType === this.config.department){
                            daysClosed=[0,1,2,3,4,5,6];

                            department.Days.forEach(function(dayDetails, dayIndex) {
                                keyedDays.forEach(function(dayName, dayMapIndex) {
                                    if(dayDetails.Day == dayName && dayDetails.OpenTime !== "Closed") {
                                        // format the data into a format that is a valid time
                                        this.dealerOpeningTimes[dayMapIndex] = {
                                            opening: this.dateTimeUtility.padTime( dayDetails.OpenTime ),
                                            closing: this.dateTimeUtility.padTime( dayDetails.CloseTime )
                                        };

                                        delete daysClosed[dayMapIndex];
                                    }
                                }.bind(this));
                            }.bind(this));
                        }
                    }.bind(this));
                }

                return daysClosed;
            },

            enumerable: false,
            writable: true
        },

        generateBookingSummary: {
            value: function() {
                if (this.booking.chosenDate !== null && this.booking.chosenTime !== null) {
                    if(this.dateTimeUtility.language.toLowerCase() === "fr-ca"){
                        this.booking.humanDate = this.dateTimeUtility.formatDate(
                        this.booking.chosenDateNonObject,
                        this.dateTimeFormats.PrettyDateFr
                        );
                    }
                    else{
                        this.booking.humanDate = this.dateTimeUtility.formatDate(
                        this.booking.chosenDateNonObject, // Hack to get us through the day :-(
                        this.dateTimeFormats.PrettyDate 
                        );
                    }
                }

                //if fr transform summary time to 24h
                if (this.dateTimeUtility.language.toLowerCase() === "fr-ca" && this.booking.chosenTime !== null ) {
                    this.booking.formattedTime =  this.formatToFrench(this.booking.formattedTime);
                }

                this.$scope.find("[data-page-section=\"booking-summary\"]").empty().html(
                  this.Templates._bookingSummary({ "Data": this.booking, "Language": this.config.language })
                );
            },

            enumerable: false,
            writable: true
        }
    });

    return AppointmentBooking;
}();

return AppointmentBooking;
});
}).apply(window);/**!!<[helper.appointment-booking]!!**/
/**!![helper.car-selector]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_bodyTypes"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, buffer = "";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.bodyTypeItems : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"2":function(depth0,helpers,partials,data) {
  var stack1, buffer = "";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.bodyTypeItems : depth0), {"name":"each","hash":{},"fn":this.program(3, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"3":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "                    <div class=\"item variant\" data-model=\""
    + escapeExpression(((helper = (helper = helpers.model || (depth0 != null ? depth0.model : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"model","hash":{},"data":data}) : helper)))
    + "\" data-model-bodytype=\""
    + escapeExpression(((helper = (helper = helpers.bodyType || (depth0 != null ? depth0.bodyType : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"bodyType","hash":{},"data":data}) : helper)))
    + "\" data-model-engine=\"";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.engineTypeList : depth0), {"name":"each","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\" data-car-id=\""
    + escapeExpression(((helper = (helper = helpers.carId || (depth0 != null ? depth0.carId : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"carId","hash":{},"data":data}) : helper)))
    + "\">\n                        <div class=\"image\">\n                            <img alt=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\" src=\""
    + escapeExpression(((helper = (helper = helpers.imageUrl || (depth0 != null ? depth0.imageUrl : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"imageUrl","hash":{},"data":data}) : helper)))
    + "\" />\n                        </div>\n                        <div class=\"details\">\n                            <div class=\"name\">"
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "</div>\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.bodyType : depth0), {"name":"if","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                            <div class=\"price\">"
    + escapeExpression(((helper = (helper = helpers.price || (depth0 != null ? depth0.price : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"price","hash":{},"data":data}) : helper)))
    + "</div>\n                        </div>\n                        <a title=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\" href=\""
    + escapeExpression(((helper = (helper = helpers.url || (depth0 != null ? depth0.url : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"url","hash":{},"data":data}) : helper)))
    + "\"></a>\n                    </div>\n";
},"4":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda(depth0, depth0))
    + ",";
},"6":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "                                <div class=\"bodytypes\">"
    + escapeExpression(((helper = (helper = helpers.bodyType || (depth0 != null ? depth0.bodyType : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"bodyType","hash":{},"data":data}) : helper)))
    + "</div>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<ul class=\"level-3\">\n    <li class=\"container\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "    </li>\n</ul>\n<div class=\"level3Bg\"></div>\n";
},"useData":true});
this["templates"]["_filter"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, buffer = "      <div class=\"row\">\n        <div class=\"title res-1600-cols-2 res-1024-cols-2\">車体タイプ</div>\n          <div class=\"filters res-1600-cols-10 res-1024-cols-10\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.bodyTypes : depth0), {"name":"each","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "          </div>\n      </div>\n";
},"2":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "            <a class=\"button filter\" title=\""
    + escapeExpression(lambda(depth0, depth0))
    + "\" href=\"#\" data-filter-bodytype=\""
    + escapeExpression(lambda(depth0, depth0))
    + "\">"
    + escapeExpression(lambda(depth0, depth0))
    + "</a>\n";
},"4":function(depth0,helpers,partials,data) {
  var stack1, buffer = "      <div class=\"row\">\n        <div class=\"title res-1600-cols-2 res-1024-cols-2\">エンジンタイプ</div>\n        <div class=\"filters res-1600-cols-10 res-1024-cols-10\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.engines : depth0), {"name":"each","hash":{},"fn":this.program(5, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "        </div>\n      </div>\n";
},"5":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "          <a class=\"button filter\" title=\""
    + escapeExpression(lambda(depth0, depth0))
    + "\" href=\"#\" data-filter-engine=\""
    + escapeExpression(lambda(depth0, depth0))
    + "\">"
    + escapeExpression(lambda(depth0, depth0))
    + "</a>\n";
},"7":function(depth0,helpers,partials,data) {
  var stack1, buffer = "      <div class=\"row\">\n        <div class=\"title res-1600-cols-2 res-1024-cols-2\">特別な機能</div>\n        <div class=\"filters res-1600-cols-10 res-1024-cols-10\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.specialFeatures : depth0), {"name":"each","hash":{},"fn":this.program(8, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "        </div>\n      </div>\n";
},"8":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "          <a class=\"button filter\" title=\""
    + escapeExpression(lambda(depth0, depth0))
    + "\" href=\"#\" data-filter-feature=\""
    + escapeExpression(lambda(depth0, depth0))
    + "\">"
    + escapeExpression(lambda(depth0, depth0))
    + "</a>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "<div class=\"container\">\n  <div class=\"res-1600-cols-12 res-1024-cols-12\">\n\n    <h3 class=\"main-title\">"
    + escapeExpression(((helper = (helper = helpers.tabTitle || (depth0 != null ? depth0.tabTitle : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tabTitle","hash":{},"data":data}) : helper)))
    + "</h3>\n\n    <div class=\"model-filters\">\n      <div class=\"sg-button model-filter-close\">\n        <a title=\"フィルター 閉じる\" class=\"button icon-close\" href=\"#\"><span class=\"visible\">フィルター 閉じる</span><span class=\"hidden\">フィルターを表示</span></a>\n      </div>\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.bodyTypes : depth0), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.engines : depth0), {"name":"if","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.specialFeatures : depth0), {"name":"if","hash":{},"fn":this.program(7, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "      <div class=\"sg-button model-filter-reset\">\n        <a title=\"すべてクリアする\" class=\"button icon-refresh\" href=\"#\">すべてクリアする</a>\n      </div>\n    </div>\n  </div>\n</div>";
},"useData":true});
this["templates"]["_grades"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "  <div class=\"item res-1600-cols-4 res-1280-cols-4 res-1024-cols-4 res-752-cols-6\">\n    <h4 class=\"title\">"
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + " <span>"
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "</span></h4>\n    <div class=\"price\">";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.from : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += escapeExpression(((helper = (helper = helpers.price || (depth0 != null ? depth0.price : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"price","hash":{},"data":data}) : helper)))
    + "</div>\n    <div class=\"description\">"
    + escapeExpression(((helper = (helper = helpers.description || (depth0 != null ? depth0.description : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"description","hash":{},"data":data}) : helper)))
    + "</div>\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.cta : depth0), {"name":"each","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "  </div>\n";
},"2":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return escapeExpression(((helper = (helper = helpers.from || (depth0 != null ? depth0.from : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"from","hash":{},"data":data}) : helper)));
  },"4":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "    <a class=\"cta\" title=\""
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "\" href=\""
    + escapeExpression(((helper = (helper = helpers.url || (depth0 != null ? depth0.url : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"url","hash":{},"data":data}) : helper)))
    + "\">"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</a>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"items\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</div>";
},"useData":true});
this["templates"]["_models"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "  <div class=\"item\" data-model-id=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\">\n    <div class=\"image\">\n      <div class=\"wrapper\">\n        <img alt=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\" src=\""
    + escapeExpression(((helper = (helper = helpers.imageUrl || (depth0 != null ? depth0.imageUrl : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"imageUrl","hash":{},"data":data}) : helper)))
    + "\" />\n      </div>\n    </div>\n    <div class=\"details\">\n      <div class=\"model\">"
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "</div>\n      <div class=\"variants\">";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.bodyTypeList : depth0), {"name":"each","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</div>\n      <div class=\"price\">"
    + escapeExpression(((helper = (helper = helpers.price || (depth0 != null ? depth0.price : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"price","hash":{},"data":data}) : helper)))
    + "</div>\n    </div>\n    <a title=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\" href=\""
    + escapeExpression(((helper = (helper = helpers.url || (depth0 != null ? depth0.url : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"url","hash":{},"data":data}) : helper)))
    + "\"></a>\n  </div>\n";
},"2":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda(depth0, depth0))
    + ", ";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1;
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { return stack1; }
  else { return ''; }
  },"useData":true});
this["templates"]["_modelsWithBodyTypes"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "  <div \n  class=\"item model";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.bodyTypeItems : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  stack1 = helpers.unless.call(depth0, (depth0 != null ? depth0.isFilterable : depth0), {"name":"unless","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\" \n  data-model-bodytype=\"";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.bodyTypeList : depth0), {"name":"each","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\"\n  data-model-engine=\"";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.engineTypeList : depth0), {"name":"each","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\"\n  data-model-feature=\"";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.specialFeaturesList : depth0), {"name":"each","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\"\n  data-default-image=\""
    + escapeExpression(((helper = (helper = helpers.imageUrl || (depth0 != null ? depth0.imageUrl : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"imageUrl","hash":{},"data":data}) : helper)))
    + "\"\n  >\n      <a title=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\" href=\""
    + escapeExpression(((helper = (helper = helpers.url || (depth0 != null ? depth0.url : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"url","hash":{},"data":data}) : helper)))
    + "\">\n      <div class=\"image\">\n        <div class=\"wrapper\">\n          <img alt=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\" src=\""
    + escapeExpression(((helper = (helper = helpers.imageUrl || (depth0 != null ? depth0.imageUrl : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"imageUrl","hash":{},"data":data}) : helper)))
    + "\" />\n        </div>\n      </div>\n      <div class=\"details\">\n        <div class=\"name\">"
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "</div>\n        ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.bodyTypeList : depth0), {"name":"if","hash":{},"fn":this.program(8, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n        <div class=\"price\">"
    + escapeExpression(((helper = (helper = helpers.price || (depth0 != null ? depth0.price : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"price","hash":{},"data":data}) : helper)))
    + "</div>\n      </div>\n    </a>\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.bodyTypeItems : depth0), {"name":"if","hash":{},"fn":this.program(10, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "  </div>\n";
},"2":function(depth0,helpers,partials,data) {
  return " hasBodyType";
  },"4":function(depth0,helpers,partials,data) {
  return " filtered";
  },"6":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda(depth0, depth0))
    + ",";
},"8":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"bodytypes\">"
    + escapeExpression(((helper = (helper = helpers.bodyTypeList || (depth0 != null ? depth0.bodyTypeList : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"bodyTypeList","hash":{},"data":data}) : helper)))
    + "</div>";
},"10":function(depth0,helpers,partials,data) {
  var stack1, buffer = "    <ul class=\"level-3\">\n      <li class=\"container\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.bodyTypeItems : depth0), {"name":"each","hash":{},"fn":this.program(11, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "      </li>\n    </ul>\n    <div class=\"level3Bg\"></div>\n";
},"11":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "        <div \n        class=\"item variant\"\n        data-model=\""
    + escapeExpression(((helper = (helper = helpers.model || (depth0 != null ? depth0.model : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"model","hash":{},"data":data}) : helper)))
    + "\"\n        data-model-bodytype=\""
    + escapeExpression(((helper = (helper = helpers.bodyType || (depth0 != null ? depth0.bodyType : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"bodyType","hash":{},"data":data}) : helper)))
    + "\" \n        data-model-engine=\"";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.engineTypeList : depth0), {"name":"each","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\"\n        data-car-id=\""
    + escapeExpression(((helper = (helper = helpers.carId || (depth0 != null ? depth0.carId : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"carId","hash":{},"data":data}) : helper)))
    + "\"\n        >\n          <div class=\"image\">\n            <img alt=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\" src=\""
    + escapeExpression(((helper = (helper = helpers.imageUrl || (depth0 != null ? depth0.imageUrl : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"imageUrl","hash":{},"data":data}) : helper)))
    + "\" />\n          </div>\n          <div class=\"details\">\n            <div class=\"name\">"
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "</div>\n            ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.bodyType : depth0), {"name":"if","hash":{},"fn":this.program(12, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n            <div class=\"price\">";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.price : depth0), {"name":"if","hash":{},"fn":this.program(14, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</div>\n          </div>\n          <a title=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\" href=\""
    + escapeExpression(((helper = (helper = helpers.url || (depth0 != null ? depth0.url : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"url","hash":{},"data":data}) : helper)))
    + "\"></a>\n        </div>\n";
},"12":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"bodytypes\">"
    + escapeExpression(((helper = (helper = helpers.bodyType || (depth0 != null ? depth0.bodyType : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"bodyType","hash":{},"data":data}) : helper)))
    + "</div>";
},"14":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return escapeExpression(((helper = (helper = helpers.price || (depth0 != null ? depth0.price : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"price","hash":{},"data":data}) : helper)))
    + " ~（税込）";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"container\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</div>";
},"useData":true});
this["templates"]["_titleArea"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"container\">\n  <div class=\"res-1600-cols-12 res-1024-cols-12\">\n\n    <h3 class=\"main-title\">"
    + escapeExpression(((helper = (helper = helpers.tabTitle || (depth0 != null ? depth0.tabTitle : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tabTitle","hash":{},"data":data}) : helper)))
    + "</h3>\n    \n  </div>\n</div>";
},"useData":true});
this["templates"]["_variants"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "    <div class=\"item variant\">\n      <div class=\"image\">\n        <img alt=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\" src=\""
    + escapeExpression(((helper = (helper = helpers.imageUrl || (depth0 != null ? depth0.imageUrl : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"imageUrl","hash":{},"data":data}) : helper)))
    + "\" />\n      </div>\n      <div class=\"details\">\n        <div class=\"name\">"
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "</div>\n        <div class=\"bodytypes\">"
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "</div>\n        <div class=\"price\">"
    + escapeExpression(((helper = (helper = helpers.price || (depth0 != null ? depth0.price : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"price","hash":{},"data":data}) : helper)))
    + "</div>\n      </div>\n      <a title=\""
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\" href=\""
    + escapeExpression(((helper = (helper = helpers.url || (depth0 != null ? depth0.url : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"url","hash":{},"data":data}) : helper)))
    + "\"></a>\n    </div>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<ul class=\"level-3\">\n  <li class=\"container\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "  </li>\n</ul>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.car-selector.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("car-selector", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var CarSelectorHelper = function() {
  "use strict";

  function CarSelectorHelper(config) {
    this.Services = new app.services();
    this.Helpers = new app.helpers();

    this.config = config;
    this.sessionService = this.Services.session;
    this.pagetools = this.Services.pagetools;
    //this.pagetools = this.Services.('pagetools');
    this.window = this.pagetools.window;

    this.Templates = {
      _filter: this.config.templates && this.config.templates._filter ? this.config.templates._filter : this.Services.templateService.templates("helper.car-selector._filter"),
      _titleArea: this.Services.templateService.templates("helper.car-selector._titleArea"),
      _models: this.config.templates && this.config.templates._models ? this.config.templates._models : this.Services.templateService.templates("helper.car-selector._models"),
      _bodyTypes: this.config.templates && this.config.templates._bodyTypes ? this.config.templates._bodyTypes : this.Services.templateService.templates("helper.car-selector._bodyTypes"),
      _grades: this.Services.templateService.templates("helper.car-selector._grades"),
      _modelsWithBodyTypes: this.config.templates && this.config.templates._modelsWithBodyTypes ? this.config.templates._modelsWithBodyTypes : this.Services.templateService.templates("helper.car-selector._modelsWithBodyTypes"),
      _carMobile: this.config.templates && this.config.templates._carMobile ? this.config.templates._carMobile : ""
    }

    if (!this.config.scope) {
      console.log("**** Error - missing scope ****");
      return;
    } else {
      this.scope = this.config.scope;
    }
    if ( (!this.config.dataEndpoint && !this.config.apiName) && !this.config.data) {
      console.log("**** Error - missing endpoint OR data ****");
    } else {
      this.init();
    }
  }

  $__Object$defineProperties(CarSelectorHelper.prototype, {
    init: {
      value: function() {
        if(this.config.data) {
          this.afterData(this.config.data);
        } else {
          var dataCallback = function (data) {
            if (this.config.includeModels) {
              var includeData = this.config.includeModels;

              data = data.map(function(model) {
                model.BodyTypes = model.BodyTypes.filter(function(bodytypes) {
                  return includeData.indexOf(bodytypes.CarId) > -1;
                });
                return model;
              }).filter(function(model) {
                return model.BodyTypes.length > 0;
              });
            }

            this.afterData(data);

            this.sessionService.get(function(data) {
              var carId = (data.Data) ? data.Data.carid : null;

              if(this.config.activeModel)
                carId = this.config.activeModel;

              if (carId && this.config.onCarSelected) {
                var bodyType = this.getBodyTypeByCarId(carId);

                setTimeout(function() {
                  this.config.onCarSelected.call(this, bodyType);
                }.bind(this),1700);
              }
            }.bind(this));
          }.bind(this);

          /*
          FIXME: Unable to use the logger as expected in a helper, no console.logs should be used.
                console.log("this.Services: ", this.Services );
                console.log("this.Services.pagetools: ", this.Services.pagetools.logger );
          */

          // Temporary redirect of api call until JP is brought into align with the newer localised API call method!
          if( typeof this.config.apiName !== "undefined" && this.config.apiName !== null) {
            setTimeout(function() {
              this.Services.api.request({
                  apiName: this.config.apiName
              }, function(result) {
                if(dataCallback) {
                  dataCallback(result);
                }
              }, function(error) {
                console.log("**** Error - API call returned error ****", error);
              });
            }.bind(this));
          }
          else {
            getData(
              this.config.dataEndpoint,
              dataCallback
            );
          }
        }
      },

      enumerable: false,
      writable: true
    },

    getBodyTypeByCarId: {
      value: function(carId) {
        var result;
        var inArray = function(value, list) {
          for (var key in list) {
            if (list[key] === value) {
              return true;
            }
          }
          return false;
        };

        if(this.config.filterModelCategories.length) {
          this.data.forEach(function(model) {
            model.BodyTypes.forEach(function(bodyType, index) {
              if (bodyType.CarId === carId && inArray(model.Category, this.config.filterModelCategories) ) {
                bodyType.imageUrl = model.ThumbnailImageUrl;
                result = bodyType;
              }
            }.bind(this));
          }.bind(this));
        }
        else {
          this.data.forEach(function(model) {
            model.BodyTypes.forEach(function(bodyType) {
              if (bodyType.CarId === carId) {
                bodyType.imageUrl = model.ThumbnailImageUrl;
                result = bodyType;
              }
            });
          });
        }
        return result;
      },

      enumerable: false,
      writable: true
    },

    afterData: {
      value: function(data) {
        this.data = (Array.isArray(data) ? data : [data]);
        this.tplData = {};
        this.hasModels = false;
        this.hasBodyTypes = false;
        this.hasGrades = false;
        this.hasFilter = false;

        for (var i = 0; i < this.config.list.length; i++) {
          if(this.config.list[i].type === "models") this.hasModels = true;

          if(this.config.list[i].type === "bodyTypes") this.hasBodyTypes = true;

          if(this.config.list[i].type === "grades") this.hasGrades = true;

          if(this.config.list[i].type === "filter") this.hasFilter = true;
        }

        if(this.config.tabs) {
          if(this.config.filterModelCategories && this.config.filterModelCategories.length > 0) {
            this.tplData.tabNames = this.getTabNamesByCategory(this.data, this.config.filterModelCategories);
          }else
          {
            this.tplData.tabNames = this.getTabNames(this.data);
          }

          this.tplData.primaryTab = this.getPrimaryTab(this.tplData.tabNames);

          /*      if(this.hasModels) {
                  this.tplData.modelData = this.getModelsByCategory(this.data, this.tplData.primaryTab);
                }*/

          this.getTabs(this.tplData, this.scope);
        }if(this.config.listCars && this.Templates._carMobile) {
          this.tplData.tabNames = this.getTabNames(this.data);
          this.tplData.primaryTab = this.getPrimaryTab(this.tplData.tabNames);
          var templateData = [];
          for(var i = 0; i<this.tplData.tabNames.length; i++){
            var obj = {
              title: this.tplData.tabNames[i],
              data: this.getModelsByCategory(this.data, this.tplData.tabNames[i])
            }
            templateData.push(obj);
          }

          this.carObj = {
            cat: templateData
          }

          var el = this.Templates._carMobile(this.carObj);

          this.scope.append(el);
        } else {
          if(this.hasGrades) {
            this.tplData.gradesData = this.getGradesByBodyType(this.data, this.config.modelName, this.config.bodyType);
            this.scope.append(this.createGradesTemplate(this.tplData.gradesData));
          }
        }

        if(this.config.callback) {
          this.config.callback();
        }
      },

      enumerable: false,
      writable: true
    },

    getTabs: {
      value: function(data, scope) {
        var intTab = 0,
            bodyTypeData,
            modelId;

        if(this.config.selectModelByCarId)
          intTab = this.findCarIdTabNumber(this.config.selectModelByCarId, data.tabNames);

        var tabConfig = {
          tabCollection: [],
          scope: scope,
          mobileEvents: true,
          tabsNotNested: this.config.tabsNotNested,
          tabsHover: this.config.tabsHover,
          mobileAsDropdown: this.config.mobileAsDropdown,
          defaultTabIndex: intTab,
          onTabInit: function (tabIndex, tabContent, ev) {
            var tabCategory = this.config.addTabViewAll && tabIndex === 0 ? null : this.tabData[tabIndex],
                modelHasFilter = false;

            if (this.hasModels) {
              this.tplData.modelData = this.getModelsByCategory(this.data, tabCategory);

              // TODO FIX INITIAL LOAD OF DATA AND PRIMARY TAB
              if(this.config.bodyTypeOnly) {
                tabContent.append(this.createBodyTemplate(this.tplData.modelData, tabCategory));
              } else {
                tabContent.append(this.createModelTemplate(this.tplData.modelData, tabCategory));
              }

              if(this.hasFilter) {
                modelHasFilter = this.isFilterRequiredByModel(this.tplData.modelData);
              }
            }

            if (modelHasFilter) {
              this.filterData = this.getFilterDataByCategory(this.data, tabCategory);
              tabContent.prepend(this.createFilterTemplate(this.filterData));
            } else {
              tabContent.prepend(this.createTitleAreaTemplate(tabCategory));
            }
            if (this.config.onTabInit) {
              this.config.onTabInit(tabIndex, tabContent, ev);
            }

            if(this.config.carsPerRow) {
              scope.find("br").remove();
              var value = this.config.carsPerRow;
              scope.find(".container .item:nth-child(" + value + "n)").after("</br>");
            }

            this.bindEvents(tabContent);
          }.bind(this),
          onTabClick: function () {
            //debugger;
            if(this.config.onTabClick) {
              this.config.onTabClick();
            }
          }.bind(this),
          afterInit: function () {
            if(this.config.afterTabInit) {
              this.config.afterTabInit();
            }
          }.bind(this)
        };

        this.tabData = data.tabNames;

        for (var i = 0; i < this.tabData.length; i++) {
          tabConfig.tabCollection.push({
              title: this.tabData[i],
            content: ""
          });
        }

        if (this.config.addTabViewAll) {
          tabConfig.tabCollection.unshift({
            title: "View All",
            content: ""
          });
          this.tabData.unshift("View All");
        }

        //this.tabConfig.tabCollection[0].content = data.modelContent;

        new (this.Helpers.tabs)(tabConfig);
      },

      enumerable: false,
      writable: true
    },

    bindEvents: {
      value: function(tabContent) {
        if (this.config.onModelClick) {
          tabContent.on("click", ".item", function (ev) {
            ev.preventDefault();

            var modelId = $(ev.currentTarget).data("modelId");

            this.config.onModelClick.apply(this, [
              tabContent, $(ev.currentTarget), modelId
            ]);
          }.bind(this));
        }
        if (this.config.HideSingleBodyType) {
          this.bindLineUpEvents();
        }
      },

      enumerable: false,
      writable: true
    },

    toggleModelPane: {
      value: function($pane) {
        if ($pane.hasClass("selected")) {
          $pane.removeClass("selected").attr("style", "");
        } else {
          $(".level-2 .model.selected").removeClass("selected").attr("style", "");
          $pane.addClass("selected");

          var level3Bottom = $pane.height() + $pane.position().top;
          var $level3 = $pane.find(".level-3");
          var $bg = $pane.find(".level3Bg");

          $bg.attr("style", "height:"+$level3.outerHeight()+"px; top:"+level3Bottom+"px; ");

          $level3.attr("style", "top:"+level3Bottom+"px; ");

          $pane.attr("style", "margin-bottom:"+($level3.outerHeight())+"px;");
        }
      },

      enumerable: false,
      writable: true
    },

    closeAllModelPanes: {
      value: function() {
        this.scope.find(".model.selected").removeClass("selected").attr("style", "");
      },

      enumerable: false,
      writable: true
    },

    bindLineUpEvents: {
      value: function() {
        var self = this;

        this.config.scope.on("click", ".level-2 .hasBodyType > a", function(ev) {
          ev.preventDefault();
          var $target = $(ev.currentTarget),
              $parent = $target.parent(".model"),
              $container = $target.closest(".container"),
              $level3 = $parent.find(".level-3"),
              $level3Items = $level3.find(".variant").length;

          if($level3Items === 1){
            self.closeAllModelPanes();
            self.scope.find(".item").removeClass("active");
            $target.closest(".item").addClass("active");
            $level3.find(".item.variant a").click();
          } else {
            self.toggleModelPane($parent);
          }
        });

        this.config.scope.on("click", ".level-3 .variant > a", function (ev) {
          ev.preventDefault();
          var $target = $(ev.currentTarget),
              $parent = $target.parent( ".variant" ),
              model = $parent.data("model"),
              bodyType = $parent.data("model-bodytype"),
              url = ev.target.href,
              carId = $parent.attr("data-car-id");

          self.sessionService.set("carid", carId, function () {
            if (self.config.onCarSelected) {
              ev.preventDefault();

              var $item = $target.closest(".item");

              if ($item.siblings().length) {
                self.scope.find(".item").removeClass("active");
                $item.addClass("active");
              }

              var bodyType = self.getBodyTypeByCarId(carId);

              self.config.onCarSelected.call(self, bodyType);
            } else {
              self.pagetools.window.location(url);
            }
          });
        });
      },

      enumerable: false,
      writable: true
    },

    filterModelsByModelId: {
      value: function(tabScope, modelId) {
        tabScope.find(".item").addClass("filtered");
        tabScope.find("[data-model-id=\""+modelId+"\"]").removeClass("filtered");
      },

      enumerable: false,
      writable: true
    },

    removeModelFilters: {
      value: function(tabScope) {
        tabScope.find(".item").removeClass("filtered");
      },

      enumerable: false,
      writable: true
    },

    createBodyTemplate: {
      value: function(data) {
        var _template = "_bodyTypes";
        if(this.config.isForm) {
          var formFilteredData = data.filter(function( obj) {
            return obj.useInForms === true;
          });
          return this.Templates[_template]({
            items: formFilteredData
          });
        }
        return this.Templates[_template]({
          items: data
        });
      },

      enumerable: false,
      writable: true
    },

    createModelTemplate: {
      value: function(data) {
        var _template = (this.hasBodyTypes ? "_modelsWithBodyTypes" : "_models");
        if(this.config.isForm){
          var formFilteredData = data.filter(function( obj ) {
            return obj.useInForms === true;
          });
          return this.Templates[_template]({
            items: formFilteredData
          });
        }
        return this.Templates[_template]({
          items: data
        });
      },

      enumerable: false,
      writable: true
    },

    createGradesTemplate: {
      value: function(data) {
        return this.Templates._grades({
          items: data
        });
      },

      enumerable: false,
      writable: true
    },

    createFilterTemplate: {
      value: function(data) {
        return this.Templates._filter(data);
      },

      enumerable: false,
      writable: true
    },

    createTitleAreaTemplate: {
      value: function(data) {
        return this.Templates._titleArea({
          tabTitle: data
        });
      },

      enumerable: false,
      writable: true
    },

    getGradesByBodyType: {
      value: function(data, modelName, bodyType) {
        return Array.prototype.concat.apply([], data.BodyTypes[0].Grades.map(function (item) {
          return {
            id: item["GradeId"],
            name: item["Name"],
            price: item["FormattedPrice"],
            description: item["Description"],
            cta: [{
              title: "CTA Coming Soon",
              url: "CTA Coming Soon"
            }]
          }
        }));
      },

      enumerable: false,
      writable: true
    },

    getFilterDataByCategory: {
      value: function(data, category) {
        var categoryId;

        var bodyTypes = Array.prototype.concat.apply([], data.filter(function (data) {
          return data.TabName === category;
        }).map(function (data) {
          categoryId = data.Category;
          return Array.prototype.concat.apply([], data.BodyTypes.filter(function (bodyType) {
            return bodyType.BodyTypeCategory != null;
          }).map(function (bodyType) {
            return bodyType.BodyTypeCategory;
          }));
        }));

        // Remove duplicates
        bodyTypes = bodyTypes.filter(function(item, i, ar){
          return ar.indexOf(item) === i;
        });

        var engines = Array.prototype.concat.apply([], data.filter(function (data) {
          return data.TabName === category;
        }).map(function (data) {
          return Array.prototype.concat.apply([], data.BodyTypes.map(function (bodyType) {
            return Array.prototype.concat.apply([], bodyType.Grades.map(function (grade) {
              return Array.prototype.concat.apply([], grade.Engines.map(function (engine) {
                return [engine.Fuel];
              }));
            }));
          }));
        }));

        // Remove duplicates
        engines = engines.filter(function(item, i, ar){
          return ar.indexOf(item) === i;
        });

        var specialFeatures = Array.prototype.concat.apply([], data.filter(function (data) {
          return data.TabName === category;
        }).map(function (data) {
          return Array.prototype.concat.apply([], data.SpecialFeatures.filter(function (special) {
            return special != undefined;
          }).map(function (special) {
            return special.Title;
          }));
        }));

        // Remove duplicates
        specialFeatures = specialFeatures.filter(function(item, i, ar){
          return ar.indexOf(item) === i;
        });

        return {
          tabTitle: category,
          category: categoryId,
          bodyTypes: bodyTypes,
          engines: engines,
          specialFeatures: specialFeatures
        }
      },

      enumerable: false,
      writable: true
    },

    getModelBodyTypesByModel: {
      value: function(data, model, modelUrl) {
        var self = this;
        var hasFilter = this.hasFilter;

        return data.map(function (data) {
          var bodyTypeUrl;
          if (!self.config.noHashtags) {
            if(data["CarId"]){
              //modelUrl += '#' + data['CarId'];
              bodyTypeUrl  = modelUrl + "#" + data["CarId"];
            }else{
              bodyTypeUrl = modelUrl;
            }
          }else{
            bodyTypeUrl = modelUrl;
          }

          return {
            name: data["BodyTypeModel"],
            model: model,
            imageUrl: data["ImageUrl"],
            price: data["FormattedPrice"],
            bodyType: data["BodyTypeCategory"],
            engineTypeList: function () {
              if(data.Grades && hasFilter) {
                return Array.prototype.concat.apply([], data.Grades.map(function (grades) {
                  return Array.prototype.concat.apply([], grades.Engines.map(function (engines) {
                    return engines.Fuel;
                  }));
                }));
              }
            },
            carId: data["CarId"],
            url: bodyTypeUrl
          }
        });
      },

      enumerable: false,
      writable: true
    },

    getModelsByCategory: {
      value: function(data, category) {
        var filteredData = [],
            hasFilter = this.hasFilter;

        if (category) {
          filteredData = data.filter(function (data) {
            if (data.TabName === category) {
              return data;
            }
          }.bind(this));
        } else {
          filteredData = data;
        }
        filteredData = filteredData.map(function (data){
          return {
            name: data.ModelName,
            imageUrl: data.ThumbnailImageUrl,
            bodyTypeList: function (){
              return data.BodyTypes.filter(function (bodyTypes){
                return bodyTypes.BodyTypeCategory != null;
              }).map(function (bodyTypeCategory) {
                return bodyTypeCategory.BodyTypeCategory;
              }).join(", ");
            },
            engineTypeList: function () {
              if(!hasFilter) {
                return;
              }

              var engineTypes = Array.prototype.concat.apply([], data.BodyTypes.map(function (bodyTypes){
                return Array.prototype.concat.apply([], bodyTypes.Grades.map(function (grades) {
                  return Array.prototype.concat.apply([], grades.Engines.map(function (engines) {
                    return engines.Fuel;
                  }));
                }));
              }));
              engineTypes = engineTypes.filter(function(item, i, ar){
                return ar.indexOf(item) === i;
              });
              return engineTypes;
            },
            specialFeaturesList: function () {
              return data.SpecialFeatures.filter(function (special) {
                return special != undefined;
              }).map(function (data) {
                return data.Title;
              });
            },
            bodyTypeItems: this.hasBodyTypes ? this.getModelBodyTypesByModel(data["BodyTypes"], data.ModelName, data.LinkUrl) : "",
            price: data["FormattedPrice"],
            url: this.config.requireAccessoryLink ? (data.AccessoryLinkUrl ? data.AccessoryLinkUrl : "") : data.LinkUrl,
            isFilterable: data.IsFilterable,
            useInForms: data.UseInForms
          }
        }.bind(this));
        return filteredData;
      },

      enumerable: false,
      writable: true
    },

    getCarIdByBodyTypeCategory: {
      value: function(data, model, bodyTypeCategory) {
        var data = data || this.data,
            carId = Array.prototype.concat.apply([], data.filter(function (data) {
              return data.ModelName === model;
            }).map(function (data) {
              return Array.prototype.concat.apply([], data.BodyTypes.filter(function (data) {
                return data.BodyTypeCategory === bodyTypeCategory;
              }).map(function (data) {
                return data.CarId;
              }));
            }));

        return carId[0];
      },

      enumerable: false,
      writable: true
    },

    findCarIdTabNumber: {
      value: function(carId, tabNames) {
        var tabNumber = 0;
        var carData = this.data.filter(function(item, i, ar){
          var car = item["BodyTypes"].filter(function(item, i, ar)
          {
            return item.CarId === carId;
          });

          return car.length >0;
        })[0];

        if(carData && carData.TabName && tabNames.length >0)
        {
          for (var i=0,  tot=tabNames.length; i < tot; i++) {
            if(carData.TabName == tabNames[i]){
              tabNumber = i;
              break;
            }
          }
        }

        return tabNumber;
      },

      enumerable: false,
      writable: true
    },

    getTabNamesByCategory: {
      value: function(data, filterList) {
        var tabnames = [];


        for (var i=0,  tot=filterList.length; i < tot; i++) {
          var tabCat = filterList[i];

          var obj = data.filter(function ( obj ) {
            return obj.Category === tabCat;
          })[0];

          if(obj && obj.TabName)
          {
            tabnames.push(obj.TabName);
          }
        }

        return tabnames.filter(function(e){
          return e;
        });
      },

      enumerable: false,
      writable: true
    },

    getTabNames: {
      value: function(data) {
        return data.map(function (data){
          return data.TabName;
        }).filter(function(item, i, ar){
          return ar.indexOf(item) === i;
        });
      },

      enumerable: false,
      writable: true
    },

    getPrimaryTab: {
      value: function(tabArray) {
        return tabArray[0];
      },

      enumerable: false,
      writable: true
    },

    isFilterRequiredByModel: {
      value: function(data) {
        return !!data.length ? data[0].isFilterable : false;
      },

      enumerable: false,
      writable: true
    }
  });

  return CarSelectorHelper;
}();

function getData(dataEndpoint, callback) {
  $.ajax({
      url: dataEndpoint
  }).done(function(data) {
    if(callback) {
      callback(data);
    }
  });
}

return CarSelectorHelper;
});
}).apply(window);/**!!<[helper.car-selector]!!**/
/**!![helper.carousel]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_arrows"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  return "<a class=\"nav-button prev\" title=\"Previous\" href=\"#\">Previous</a>\n<a class=\"nav-button next\" title=\"Next\" href=\"#\">Next</a>";
  },"useData":true});
this["templates"]["_arrowsContainer"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"navigationContainer\">\n	<img class=\"spacer\" src=\""
    + escapeExpression(((helper = (helper = helpers.img || (depth0 != null ? depth0.img : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"img","hash":{},"data":data}) : helper)))
    + "\">\n	<a class=\"nav-button prev\" title=\"Previous\" href=\"#\">Previous</a>\n	<a class=\"nav-button next\" title=\"Next\" href=\"#\">Next</a>\n	<div class=\"container zoom-zoom-container\">\n		<div class=\"zoom-zoom\"></div>\n	</div>\n</div>";
},"useData":true});
this["templates"]["_info"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"info\">\n    <div class=\"current\">"
    + escapeExpression(((helper = (helper = helpers.current || (depth0 != null ? depth0.current : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"current","hash":{},"data":data}) : helper)))
    + "</div>\n    <div class=\"total\">/"
    + escapeExpression(((helper = (helper = helpers.total || (depth0 != null ? depth0.total : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"total","hash":{},"data":data}) : helper)))
    + "</div>\n</div>";
},"useData":true});
this["templates"]["_pagination"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "            <li>\n                <a title=\""
    + escapeExpression(((helper = (helper = helpers.Title || (depth0 != null ? depth0.Title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"Title","hash":{},"data":data}) : helper)))
    + "\" href=\"#\">\n                    <span></span>\n                </a>\n            </li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"pagination\">\n    <ul>\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "    </ul>\n</div>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.carousel.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("carousel", function(application) {
/**
 * @class SwipeEvents
 * @classdesc Adds Swipe functionality to a given element. Only for horizontal swipes.
 * A vertical swipe is always considered a scroll event.
 */
var $__Object$defineProperties = Object.defineProperties;

var SwipeEvents = function() {
    "use strict";

    function SwipeEvents(config) {
        // Defaults
        this.touch = false;
        this.action = false;
        this.scroll = false;
        this.sort = false;
        this.swipe = false;
        this.tap = false;
        this.diffX = 0;
        this.diffY = 0;
        this.endX = 0;
        this.endY = 0;
        this.startX = 0;
        this.startY = 0;
        this.swipeDirection = "";

        // Default Config
        this.config = {
            tapDelay: 500,
            sortDelay: 200,
            scrollThreshold: 10,
            swipeThreshold: 7,
            sortThreshold: 5
        }
        this.config = $.extend(this.config, config);

        // Config for Touch/Pointer events
        if (window.navigator.pointerEnabled) {
            this.touchStart = "pointerdown";
            this.touchMove = "pointermove";
            this.touchEnd = "pointerup";
            this.touchCancel = "pointercancel";
        } else if (window.navigator.msPointerEnabled) {
            this.touchStart = "MSPointerDown";
            this.touchMove = "MSPointerMove";
            this.touchEnd = "MSPointerUp";
            this.touchCancel = "MSPointerCancel";
        } else {
            this.touchStart = "touchstart";
            this.touchMove = "touchmove";
            this.touchEnd = "touchend";
            this.touchCancel = "touchcancel";
        }

        this.init();
    }

    $__Object$defineProperties(SwipeEvents.prototype, {
        init: {
            value: function() {
                this.scope = this.config.scope instanceof $ ? this.config.scope : $(this.config.scope);
                // Disable elements mouse drag for swipes with mousemove
                this.disableElementDrag();
                this.scope.on(this.touchStart + " mousedown", function(event) {
                    this.onStart(event);
                }.bind(this))
                          .on(this.touchMove, function(event) {
                    this.onMove(event);
                }.bind(this))
                          .on(this.touchEnd + " " + this.touchCancel, function(event) {
                    this.onEnd(event);
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        getCoord: {
            value: function(event, c) {
                return /touch/.test(event.type) ? (event.originalEvent || event).changedTouches[0]["page" + c] : (event.originalEvent || event)["client" + c];
            },

            enumerable: false,
            writable: true
        },

        setTap: {
            value: function() {
                this.tap = true;
                setTimeout(function() {
                    this.tap = false;
                }.bind(this), this.config.tapDelay);
            },

            enumerable: false,
            writable: true
        },

        testTouch: {
            value: function(event) {
                if (event.type.match(this.touchStart)) {
                    this.touch = true;
                } else if (this.touch) {
                    this.touch = false;
                    return false;
                }
                return true;
            },

            enumerable: false,
            writable: true
        },

        onStart: {
            value: function(event) {
                if (this.testTouch(event) && !this.action) {
                    this.action = true;

                    this.startX = this.getCoord(event, "X");
                    this.startY = this.getCoord(event, "Y");

                    this.sortTimer = setTimeout(function() {
                        this.sort = true;
                    }.bind(this), this.config.sortDelay);

                    if (event.type == "mousedown") {
                        this.scope.on("mousemove.swipe", function(event) {
                            event.preventDefault();
                            this.onMove(event);
                        }.bind(this)).on("mouseup.swipe", function(event) {
                            this.onEnd(event);
                        }.bind(this));
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        onMove: {
            value: function(event) {
                if (this.action) {
                    this.endX = this.getCoord(event, "X");
                    this.endY = this.getCoord(event, "Y");
                    this.diffX = this.endX - this.startX;
                    this.diffY = this.endY - this.startY;

                    if (!this.sort && !this.swipe && !this.scroll) {
                        if (Math.abs(this.diffY) > this.config.scrollThreshold) {
                            // It's a scroll
                            this.scroll = true;
                            this.swipeDirection = "";
                            // Android 4.0 will not fire touchend event
                            this.scope.trigger(this.touchEnd);
                            this.scope.trigger(this.touchCancel);
                            this.scope.trigger("mouseup");
                        } else if (Math.abs(this.diffX) > this.config.swipeThreshold) {
                            // It's a swipe
                            this.swipe = true;
                            this.setSwipeDirection();
                        }
                    }

                    if (this.swipe) {
                        // Kill page scroll
                        event.preventDefault();
                        // Handle swipe
                        if (this.config.onSwipe) {
                            this.config.onSwipe.call(this, this.swipeDirection);
                        }
                    }

                    if (this.sort) {
                        // Kill page scroll
                        // Handle sort
                        event.preventDefault();
                    }

                    if (Math.abs(this.diffX) > this.config.sortThreshold || Math.abs(this.diffY) > this.config.sortThreshold) {
                        clearTimeout(this.sortTimer);
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        onEnd: {
            value: function(event) {
                if (this.action) {
                    this.action = false;

                    if (this.swipe) {
                        // Handle swipe end
                        if (this.config.afterSwipe) {
                            this.config.afterSwipe.call(this, this.swipeDirection);
                        }
                    } else if (this.sort) {} else if (!this.scroll && Math.abs(this.diffX) < this.config.sortThreshold && Math.abs(this.diffY) < this.config.sortThreshold) {
                        // Tap
                        // Handle tap
                        // ...
                        if (event.type.match(this.touchEnd)) {
                            // Prevent phantom clicks
                            event.preventDefault();
                        }
                    }

                    this.swipe = false;
                    this.sort = false;
                    this.scroll = false;

                    clearTimeout(this.sortTimer);

                    if (event.type == "mouseup") {
                        this.scope.off("mousemove.swipe").off("mouseup.swipe");
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        setSwipeDirection: {
            value: function() {
                this.swipeDirection = this.endX > this.startX ? "right" : "left";
            },

            enumerable: false,
            writable: true
        },

        disableElementDrag: {
            value: function() {
                var images = this.scope.find("img"),
                    links = this.scope.find("a"),
                    _undrag = function ($elements) {
                        if ($elements.length > 0) {
                            $elements.attr("draggable", "false");
                        }
                    };
                _undrag(images);
                _undrag(links);
            },

            enumerable: false,
            writable: true
        }
    });

    return SwipeEvents;
}();
var $__Object$defineProperties = Object.defineProperties;

var Carousel = function() {
    "use strict";

    function Carousel(config) {
        var Services = new app.services(),
            templates = Services.templateService.templates;

        this.Templates = {
            _arrows: templates("helper.carousel._arrows"),
            _arrowsContainer: templates("helper.carousel._arrowsContainer"),
            _pagination: templates("helper.carousel._pagination"),
            _info: templates("helper.carousel._info")
        }

        // Inputs and defaults
        this.config = config;
        this.setTimer();

        if (!this.config.scope) {
            console.log("Scope is required");
            return;
        }

        this.$scope = $(this.config.scope);
        this.config.defaultItem = this.config.defaultItem || 0;
        this.config.autoRotationTimer = this.config.autoRotationTimer || 0;
        this.config.rotationDuration = this.config.rotationDuration || 400;
        this.config.showInfo = this.config.showInfo;
        this.config.autoRotationStop = this.config.autoRotationStop || false;

        if( (typeof this.config.enableSwipeEvents == "undefined") || (this.config.enableSwipeEvents === true) ){
            this.config.enableSwipeEvents = true;
        }else{
            this.config.enableSwipeEvents = false;
        }

        // State variables
        this.currentItem = 0;
        this.itemPosition = 0;
        this.offset = 0;
        // Default
        this.carouselOffset = 100;
        // Process carousel template
        this.$list = this.$scope.children(".slides");
        this.$items = this.$list.children("li");
        this.count = this.$items.length;

        this.stopTimer = this.stopTimer.bind(this);
        this.restartTimer = this.restartTimer.bind(this);

        // Run carousel initialisation, if there are any items to show
        if (this.count > 1) {
            // Get titles
            this.titles = [];

            for (var i = 0; i < this.$items.length; i++) {
                this.titles.push(this.$items.find(".title").html());
            }
            setTimeout(function() {
                this.pagetools = Services.pagetools;
                this.isMobile = this.pagetools.window.isMobile();
                this.init();
            }.bind(this));
        } else {
            this.$list.wrap("<div class=\"slides-wrapper\" />");
        }
    }

    $__Object$defineProperties(Carousel.prototype, {
        init: {
            value: function() {
                var self = this;

                this.thumb = this.config.isThumbnail;
                // Wrap carousel
                this.$list.wrap("<div class=\"slides-wrapper\" />");
                // Add helper class
                this.$list.parent(".slides-wrapper").addClass("helper-carousel");
                this.$slidesWrapper = this.$list.parent(".slides-wrapper");

                if(this.config.navigationCentered && this.config.navigationCentered !== "relative"){
                    //Render arrows in separate li
                    var imgSrc = this.$slidesWrapper.find("ul.slides li").first().find("img").attr("src");
                    var navigationElement = this.Templates._arrowsContainer({
                        img: imgSrc
                    });
                    this.$slidesWrapper.find("ul.slides").after($(navigationElement));
                } else if (this.config.navigationCentered === "relative") {
                    // Render navigation arrows
                    var arrowsHtml = this.Templates._arrows();
                    this.$slidesWrapper.append($(arrowsHtml));
                } else {
                    // Render navigation arrows
                    var arrowsHtml = this.Templates._arrows();
                    this.$slidesWrapper.after($(arrowsHtml));
                }

                // Render pagination, unless explicitely set to not render
                this.renderPagination();

                // Adjust sizes
                this.adjustSizes();
                this.adjustOnResize();

                if (this.$scope.find(".navigationContainer").length){
                    this.$navigationPrevious = this.$scope.find(".navigationContainer").find(".nav-button.prev");
                    this.$navigationNext = this.$scope.find(".navigationContainer").find(".nav-button.next");
                } else {
                    this.$navigationPrevious = $(this.$scope.find(".nav-button.prev")[0]);
                    this.$navigationNext = $(this.$scope.find(".nav-button.next")[0]);
                }

                this.$paginationLinks = this.$scope.find(".pagination a");

                this.$navigationNext.on("click", function(e){
                    e.preventDefault();
                    self.nextItem(1, true);
                });

                this.$navigationPrevious.on("click", function(e){
                    e.preventDefault();
                    self.previousItem(1, true);
                });

                this.$paginationLinks.on("click", function(e) {
                    e.preventDefault();
                    var $this = $(e.currentTarget);
                    this.navigateTo($this.parent().index(), true);
                }.bind(this));

                if (this.config.enableSwipeEvents) {
                    this.bindSwipeEvents();
                }

                // Set rotation timer
                //this.setTimer();

                this.navigateTo(this.config.defaultItem);
                this.setCurrentItem(this.config.defaultItem);

                // Render navigation info
                if (this.config.showInfo) {
                    this.$info = [];
                    this.refreshInfo();
                }

                if (this.config.onAfterInit) {
                    this.config.onAfterInit.apply(this, arguments);
                }

                if(this.config.autoRotationTimer > 0 && this.config.autoRotationStop)
                    this.stopTimeEvents();
            },

            enumerable: false,
            writable: true
        },

        setTimer: {
            value: function() {
                if (this.config.autoRotationTimer) {
                    this.timer = setInterval(function() {
                        this.nextItem();
                    }.bind(this), this.config.autoRotationTimer);
                }
            },

            enumerable: false,
            writable: true
        },

        resetTimer: {
            value: function() {
                if (this.config.autoRotationTimer) {
                    clearInterval(this.timer);
                    this.setTimer();
                }
            },

            enumerable: false,
            writable: true
        },

        stopTimer: {
            value: function() {
                if (this.config.autoRotationTimer)
                    clearInterval(this.timer);
            },

            enumerable: false,
            writable: true
        },

        restartTimer: {
            value: function() {
                if (this.config.autoRotationTimer){
                    clearInterval(this.timer);
                    this.setTimer();
                    this.nextItem();
                }
            },

            enumerable: false,
            writable: true
        },

        stopTimeEvents: {
            value: function() {
                this.$scope.on("mouseout", function() {
                    clearInterval(this.timer);
                    this.setTimer();
                }.bind(this));

                this.$scope.on("mouseover", function() {
                    clearInterval(this.timer);
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        renderPagination: {
            value: function() {
                var renderPagination =
                    typeof this.config.renderPagination === "undefined" ?
                    true : this.config.renderPagination;

                if (renderPagination) {
                    var paginationHtml = this.Templates._pagination({
                        items: this.titles
                    });
                    this.$scope.append($(paginationHtml));
                }
            },

            enumerable: false,
            writable: true
        },

        adjustSizes: {
            value: function(reset) {
                var itemsWidth = 0,
                    listWidth = 100,
                    lastItemWidth = 0,
                    _usePixels = function() {
                        return 100 % this.count !== 0 && this.isMobile;
                    }.bind(this),
                    _roundToDecimals = function(number) {
                        return window.Math.round(number * 1000) / 1000;
                    },
                    _calculateItemsWidth = function() {
                        var rawItemsWidth = 100 / this.count;
                        return this.isMobile ?
                            _roundToDecimals(rawItemsWidth) :
                            rawItemsWidth;
                    }.bind(this),
                    _adjustSizes = function(unit) {
                        this.$list.width(listWidth * this.count + unit);
                        this.$items.width(itemsWidth + unit);
                    }.bind(this),
                    unit = "%";

                // Reset the list wrapper width for resizing
                this.$list.parent().css("width", "");


                if(this.config.usePixels){
                    this.usePixels = true;
                }else{
                    this.usePixels = _usePixels();
                }

                itemsWidth = _calculateItemsWidth();

                // Set initial sizes in percentages
                _adjustSizes(unit);

                if (this.usePixels) {
                    unit = "px";
                    itemsWidth = this.$items.first().width();
                    // Prevent jQuery incorrect return of width
                    if (_roundToDecimals(itemsWidth) !== _roundToDecimals(_calculateItemsWidth())) {
                        listWidth = itemsWidth;
                        this.carouselOffset = itemsWidth;
                        // Recalculate the slides position on resize, due to pixel values
                        if (reset) {
                            var itemPosition = $(this.$items[this.currentItem]).index(),
                                offset = -1 * itemPosition * this.carouselOffset,
                                newMaxOffset = -1 * itemsWidth * (this.count - 1),
                                currentMaxOffset = -1 * this.itemsPixelWidth * (this.count - 1);
                            if (this.offset !== 0) {
                                if (this.offset !== currentMaxOffset) {
                                    this.offset = offset;
                                } else {
                                    this.offset = newMaxOffset;
                                }
                            }
                            this.updateOffset(0);
                        }
                        // Store the current items width in pixels, to check if it is on max offset before resizing
                        this.itemsPixelWidth = itemsWidth;
                        // Set the list wrapper width to prevent subpixel rendering issues
                        this.$list.parent().css("width", itemsWidth + "px");
                        _adjustSizes(unit);
                    } else {
                        this.usePixels = false;
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        adjustOnResize: {
            value: function() {
                if (this.usePixels) {
                    $(window).on("resize.carousel", function() {
                        this.isMobile = this.pagetools.window.isMobile();
                        this.adjustSizes(true);
                    }.bind(this));
                }
            },

            enumerable: false,
            writable: true
        },

        updateOffset: {
            value: function(offset, instant) {
                this.offset += offset;
                var unit = this.usePixels ? "px" : "%";

                if (instant) {
                    this.$list.css("left", this.offset + unit);
                } else {
                    var animate = $().velocity ? "velocity" : "animate";
                    this.$list[animate]({
                        left: this.offset + unit
                    }, this.config.rotationDuration);
                }
            },

            enumerable: false,
            writable: true
        },

        setSelectedListItem: {
            value: function(selectedItem) {
                $(selectedItem).closest(".slides").find("li.selected").removeClass("selected");
                $(selectedItem).addClass("selected");
            },

            enumerable: false,
            writable: true
        },

        setCurrentItem: {
            value: function(index) {
                this.currentItem = index;

                if(this.$paginationLinks){
                    this.$paginationLinks.removeClass("active");
                    $(this.$paginationLinks[index]).addClass("active");
                }

                if (this.config.afterCurrentItemSet) {
                    this.config.afterCurrentItemSet.apply(this, [
                        index
                    ]);
                }
            },

            enumerable: false,
            writable: true
        },

        previousItem: {
            value: function(multiplier, shouldReset) {
                var rotate = typeof multiplier === "undefined";

                multiplier = multiplier || 1;

                if (this.currentItem - multiplier > 0) {
                    this.setCurrentItem(this.currentItem - multiplier);
                } else if (this.currentItem - multiplier < 0) {
                    this.setCurrentItem(
                        this.count - Math.abs(this.currentItem - multiplier)
                    );
                } else {
                    this.setCurrentItem(0);
                }

                var itemPosition = $(this.$items[this.currentItem]).index();

                this.setSelectedListItem(this.$items[this.currentItem]);

                if (itemPosition === this.count - 1) {
                    var $firstItem = this.$list.children("li:first"),
                        $lastItem = this.$list.children("li:last");

                    $firstItem.before($lastItem);

                    this.updateOffset(-this.carouselOffset, true);
                }


                this.updateOffset(this.carouselOffset * multiplier);

                if (shouldReset) this.resetTimer();

                if (this.config.onItemNavigateStart) {
                    this.config.onItemNavigateStart.apply(this, [this.currentItem]);
                }

                this.refreshInfo();
            },

            enumerable: false,
            writable: true
        },

        nextItem: {
            value: function(multiplier, shouldReset) {
                var rotate = typeof multiplier === "undefined";

                multiplier = multiplier || 1;

                if (this.currentItem + multiplier < this.count - 1) {
                    this.setCurrentItem(this.currentItem + multiplier);
                } else {
                    this.setCurrentItem((this.currentItem + multiplier) % this.count);
                }

                var itemPosition = $(this.$items[this.currentItem]).index();

                this.setSelectedListItem($(this.$items[this.currentItem]));

                if (itemPosition === 0) {
                    var $firstItem = this.$list.children("li:first"),
                        $lastItem = this.$list.children("li:last");

                    $lastItem.after($firstItem);

                    this.updateOffset(this.carouselOffset, true);
                }

                this.updateOffset(-this.carouselOffset * multiplier);

                if (shouldReset) this.resetTimer();

                if (this.config.onItemNavigateStart) {
                    this.config.onItemNavigateStart.apply(this, [this.currentItem]);
                }
                this.refreshInfo();
            },

            enumerable: false,
            writable: true
        },

        navigateTo: {
            value: function(itemIndex, shouldReset) {
                var $items = this.$items,
                    currentItem = this.currentItem,
                    currentItemPosition = $($items[currentItem]).index(),
                    newItemPosition = $($items[itemIndex]).index(),
                    delta = newItemPosition - currentItemPosition;

                if (delta > 0) {
                    this.nextItem(delta, shouldReset);
                } else if (delta < 0) {
                    this.previousItem(Math.abs(delta), shouldReset);
                }
            },

            enumerable: false,
            writable: true
        },

        getItemCount: {
            value: function() {
                return this.count;
            },

            enumerable: false,
            writable: true
        },

        refreshInfo: {
            value: function() {
                if (this.$info) {
                    var _integerToTwoDigits = function(integer) {
                        return integer < 10 ? "0" + integer : integer.toString();
                    }

                    var infoHtml = this.Templates._info({
                        current: _integerToTwoDigits(this.currentItem + 1),
                        total: _integerToTwoDigits(this.count)
                    });

                    this.$info = this.$scope.find(".info");

                    if (!this.$info.length) {
                        this.$slidesWrapper.before(infoHtml);
                    } else {
                        this.$info.replaceWith(infoHtml);
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        bindSwipeEvents: {
            value: function() {
                if (SwipeEvents) {
                    var _swipes = function(direction) {
                        if (direction === "right") {
                            this.previousItem();
                        } else if (direction === "left") {
                            this.nextItem();
                        }
                    }.bind(this);

                    this.swipeItems = new SwipeEvents({
                        scope: this.$items,
                        afterSwipe: function(direction) {
                            _swipes(direction);
                        }
                    });
                }
            },

            enumerable: false,
            writable: true
        }
    });

    return Carousel;
}();

return Carousel;
});
}).apply(window);/**!!<[helper.carousel]!!**/
/**!![helper.copyright-overlay]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_info"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  return "<div class=\"helper-copyright-overlay\">\n	<div class=\"info-popup\">\n		<div class=\"container popup\">\n\n			<div class=\"text-area scrollbar-inner\">\n\n				<div class=\"inner\">\n\n				</div>	\n\n			</div>\n\n			<div class=\"close-btn\">Close</div>\n\n		</div>\n	</div>\n\n</div>";
  },"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.copyright-overlay.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("copyright-overlay", function(application) {
/*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh)
* Licensed under the MIT License (LICENSE.txt).
*
* Version: 3.1.12
*
* Requires: jQuery 1.2.2+
*/



(function (factory) {
    if ( typeof define === "function" && define.amd ) {
        // AMD. Register as an anonymous module.
        define(["jquery"], factory);
    } else if (typeof exports === "object") {
        // Node/CommonJS style for Browserify
        module.exports = factory;
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {
    var toFix  = ["wheel", "mousewheel", "DOMMouseScroll", "MozMousePixelScroll"],
        toBind = ( "onwheel" in document || document.documentMode >= 9 ) ?
                    ["wheel"] : ["mousewheel", "DomMouseScroll", "MozMousePixelScroll"],
        slice  = Array.prototype.slice,
        nullLowestDeltaTimeout, lowestDelta;

    if ( $.event.fixHooks ) {
        for ( var i = toFix.length; i; ) {
            $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
        }
    }

    var special = $.event.special.mousewheel = {
        version: "3.1.12",

        setup: function() {
            if ( this.addEventListener ) {
                for ( var i = toBind.length; i; ) {
                    this.addEventListener( toBind[--i], handler, false );
                }
            } else {
                this.onmousewheel = handler;
            }
            // Store the line height and page height for this particular element
            $.data(this, "mousewheel-line-height", special.getLineHeight(this));
            $.data(this, "mousewheel-page-height", special.getPageHeight(this));
        },

        teardown: function() {
            if ( this.removeEventListener ) {
                for ( var i = toBind.length; i; ) {
                    this.removeEventListener( toBind[--i], handler, false );
                }
            } else {
                this.onmousewheel = null;
            }
            // Clean up the data we added to the element
            $.removeData(this, "mousewheel-line-height");
            $.removeData(this, "mousewheel-page-height");
        },

        getLineHeight: function(elem) {
            var $elem = $(elem),
                $parent = $elem["offsetParent" in $.fn ? "offsetParent" : "parent"]();
            if (!$parent.length) {
                $parent = $("body");
            }
            return parseInt($parent.css("fontSize"), 10) || parseInt($elem.css("fontSize"), 10) || 16;
        },

        getPageHeight: function(elem) {
            return $(elem).height();
        },

        settings: {
            adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
            normalizeOffset: true  // calls getBoundingClientRect for each event
        }
    };

    $.fn.extend({
        mousewheel: function(fn) {
            return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
        },

        unmousewheel: function(fn) {
            return this.unbind("mousewheel", fn);
        }
    });


    function handler(event) {
        var orgEvent   = event || window.event,
            args       = slice.call(arguments, 1),
            delta      = 0,
            deltaX     = 0,
            deltaY     = 0,
            absDelta   = 0,
            offsetX    = 0,
            offsetY    = 0;
        event = $.event.fix(orgEvent);
        event.type = "mousewheel";

        // Old school scrollwheel delta
        if ( "detail"      in orgEvent ) {
            deltaY = orgEvent.detail * -1;
        }
        if ( "wheelDelta"  in orgEvent ) {
            deltaY = orgEvent.wheelDelta;
        }
        if ( "wheelDeltaY" in orgEvent ) {
            deltaY = orgEvent.wheelDeltaY;
        }
        if ( "wheelDeltaX" in orgEvent ) {
            deltaX = orgEvent.wheelDeltaX * -1;
        }

        // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
        if ( "axis" in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
            deltaX = deltaY * -1;
            deltaY = 0;
        }

        // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
        delta = deltaY === 0 ? deltaX : deltaY;

        // New school wheel delta (wheel event)
        if ( "deltaY" in orgEvent ) {
            deltaY = orgEvent.deltaY * -1;
            delta  = deltaY;
        }
        if ( "deltaX" in orgEvent ) {
            deltaX = orgEvent.deltaX;
            if ( deltaY === 0 ) {
                delta  = deltaX * -1;
            }
        }

        // No change actually happened, no reason to go any further
        if ( deltaY === 0 && deltaX === 0 ) {
            return;
        }

        // Need to convert lines and pages to pixels if we aren't already in pixels
        // There are three delta modes:
        //   * deltaMode 0 is by pixels, nothing to do
        //   * deltaMode 1 is by lines
        //   * deltaMode 2 is by pages
        if ( orgEvent.deltaMode === 1 ) {
            var lineHeight = $.data(this, "mousewheel-line-height");
            delta  *= lineHeight;
            deltaY *= lineHeight;
            deltaX *= lineHeight;
        } else if ( orgEvent.deltaMode === 2 ) {
            var pageHeight = $.data(this, "mousewheel-page-height");
            delta  *= pageHeight;
            deltaY *= pageHeight;
            deltaX *= pageHeight;
        }

        // Store lowest absolute delta to normalize the delta values
        absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );

        if ( !lowestDelta || absDelta < lowestDelta ) {
            lowestDelta = absDelta;

            // Adjust older deltas if necessary
            if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
                lowestDelta /= 40;
            }
        }

        // Adjust older deltas if necessary
        if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
            // Divide all the things by 40!
            delta  /= 40;
            deltaX /= 40;
            deltaY /= 40;
        }

        // Get a whole, normalized value for the deltas
        delta  = Math[ delta  >= 1 ? "floor" : "ceil" ](delta  / lowestDelta);
        deltaX = Math[ deltaX >= 1 ? "floor" : "ceil" ](deltaX / lowestDelta);
        deltaY = Math[ deltaY >= 1 ? "floor" : "ceil" ](deltaY / lowestDelta);

        // Normalise offsetX and offsetY properties
        if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
            var boundingRect = this.getBoundingClientRect();
            offsetX = event.clientX - boundingRect.left;
            offsetY = event.clientY - boundingRect.top;
        }

        // Add information to the event object
        event.deltaX = deltaX;
        event.deltaY = deltaY;
        event.deltaFactor = lowestDelta;
        event.offsetX = offsetX;
        event.offsetY = offsetY;
        // Go ahead and set deltaMode to 0 since we converted to pixels
        // Although this is a little odd since we overwrite the deltaX/Y
        // properties with normalized deltas.
        event.deltaMode = 0;

        // Add event and delta to the front of the arguments
        args.unshift(event, delta, deltaX, deltaY);

        // Clearout lowestDelta after sometime to better
        // handle multiple device types that give different
        // a different lowestDelta
        // Ex: trackpad = 3 and mouse wheel = 120
        if (nullLowestDeltaTimeout) {
            clearTimeout(nullLowestDeltaTimeout);
        }
        nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);

        return ($.event.dispatch || $.event.handle).apply(this, args);
    }

    function nullLowestDelta() {
        lowestDelta = null;
    }

    function shouldAdjustOldDeltas(orgEvent, absDelta) {
        // If this is an older event and the delta is divisable by 120,
        // then we are assuming that the browser is treating this as an
        // older mouse wheel event and that we should divide the deltas
        // by 40 to try and get a more usable deltaFactor.
        // Side note, this actually impacts the reported scroll distance
        // in older browsers and can cause scrolling to be slower than native.
        // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
        return special.settings.adjustOldDeltas && orgEvent.type === "mousewheel" && absDelta % 120 === 0;
    }
}));
/**
 * jQuery CSS Customizable Scrollbar
 *
 * Copyright 2015, Yuriy Khabarov
 * Dual licensed under the MIT or GPL Version 2 licenses.
 *
 * If you found bug, please contact me via email <13real008@gmail.com>
 *
 * @author Yuriy Khabarov aka Gromo
 * @version 0.2.8
 * @url https://github.com/gromo/jquery.scrollbar/
 *
 */


(function (root, factory) {
    /* if (typeof define === 'function' && define.amd) {
         define(['jquery'], factory);
     } else {*/
    //factory(root.jQuery);
    //}
    factory(jQuery);
}(this, function ($) {
    //'use strict';

    // init flags & variables
    var debug = false;

    var browser = {
        data: {
            index: 0,
            name: "scrollbar"
        },
        macosx: navigator.platform.toLowerCase().indexOf("mac") !== -1,
        mobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent),
        overlay: null,
        scroll: null,
        scrolls: [],
        webkit: /WebKit/.test(navigator.userAgent)
    };

    browser.scrolls.add = function (instance) {
        this.remove(instance).push(instance);
    };
    browser.scrolls.remove = function (instance) {
        while ($.inArray(instance, this) >= 0) {
            this.splice($.inArray(instance, this), 1);
        }
        return this;
    };

    var defaults = {
        "autoScrollSize": true,     // automatically calculate scrollsize
        "autoUpdate": true,         // update scrollbar if content/container size changed
        "debug": false,             // debug mode
        "disableBodyScroll": false, // disable body scroll if mouse over container
        "duration": 200,            // scroll animate duration in ms
        "ignoreMobile": false,      // ignore mobile devices
        "ignoreOverlay": false,     // ignore browsers with overlay scrollbars (mobile, MacOS)
        "scrollStep": 30,           // scroll step for scrollbar arrows
        "showArrows": false,        // add class to show arrows
        "stepScrolling": true,      // when scrolling to scrollbar mousedown position

        "scrollx": null,            // horizontal scroll element
        "scrolly": null,            // vertical scroll element

        "onDestroy": null,          // callback function on destroy,
        "onInit": null,             // callback function on first initialization
        "onScroll": null,           // callback function on content scrolling
        "onUpdate": null            // callback function on init/resize (before scrollbar size calculation)
    };


    var BaseScrollbar = function (container) {
        if (!browser.scroll) {
            browser.overlay = isScrollOverlaysContent();
            browser.scroll = getBrowserScrollSize();
            updateScrollbars();

            $(window).resize(function () {
                var forceUpdate = false;
                if (browser.scroll && (browser.scroll.height || browser.scroll.width)) {
                    var scroll = getBrowserScrollSize();
                    if (scroll.height !== browser.scroll.height || scroll.width !== browser.scroll.width) {
                        browser.scroll = scroll;
                        // handle page zoom
                        forceUpdate = true;
                    }
                }
                updateScrollbars(forceUpdate);
            });
        }

        this.container = container;
        this.namespace = ".scrollbar_" + browser.data.index++;
        this.options = $.extend({}, defaults, window.jQueryScrollbarOptions || {});
        this.scrollTo = null;
        this.scrollx = {};
        this.scrolly = {};

        container.data(browser.data.name, this);
        browser.scrolls.add(this);
    };

    BaseScrollbar.prototype = {

        destroy: function () {
            if (!this.wrapper) {
                return;
            }

            this.container.removeData(browser.data.name);
            browser.scrolls.remove(this);

            // init variables
            var scrollLeft = this.container.scrollLeft();
            var scrollTop = this.container.scrollTop();

            this.container.insertBefore(this.wrapper).css({
                "height": "",
                "margin": "",
                "max-height": ""
            })
                .removeClass("scroll-content scroll-scrollx_visible scroll-scrolly_visible")
                .off(this.namespace)
                .scrollLeft(scrollLeft)
                .scrollTop(scrollTop);

            this.scrollx.scroll.removeClass("scroll-scrollx_visible").find("div").andSelf().off(this.namespace);
            this.scrolly.scroll.removeClass("scroll-scrolly_visible").find("div").andSelf().off(this.namespace);

            this.wrapper.remove();

            $(document).add("body").off(this.namespace);

            if ($.isFunction(this.options.onDestroy)){
                this.options.onDestroy.apply(this, [this.container]);
            }
        },
        init: function (options) {
            // init variables
            var S = this,
                c = this.container,
                cw = this.containerWrapper || c,
                namespace = this.namespace,
                o = $.extend(this.options, options || {}),
                s = {x: this.scrollx, y: this.scrolly},
                w = this.wrapper;

            var initScroll = {
                "scrollLeft": c.scrollLeft(),
                "scrollTop": c.scrollTop()
            };

            // do not init if in ignorable browser
            if ((browser.mobile && o.ignoreMobile)
                || (browser.overlay && o.ignoreOverlay)
                || (browser.macosx && !browser.webkit) // still required to ignore nonWebKit browsers on Mac
                ) {
                return false;
            }

            // init scroll container
            if (!w) {
                this.wrapper = w = $("<div>").addClass("scroll-wrapper").addClass(c.attr("class"))
                    .css("position", c.css("position") == "absolute" ? "absolute" : "relative")
                    .insertBefore(c).append(c);

                if (c.is("textarea")) {
                    this.containerWrapper = cw = $("<div>").insertBefore(c).append(c);
                    w.addClass("scroll-textarea");
                }

                cw.addClass("scroll-content").css({
                    "height": "auto",
                    "margin-bottom": browser.scroll.height * -1 + "px",
                    "margin-right": browser.scroll.width * -1 + "px",
                    "max-height": ""
                });

                c.on("scroll" + namespace, function (event) {
                    if ($.isFunction(o.onScroll)) {
                        o.onScroll.call(S, {
                            "maxScroll": s.y.maxScrollOffset,
                            "scroll": c.scrollTop(),
                            "size": s.y.size,
                            "visible": s.y.visible
                        }, {
                            "maxScroll": s.x.maxScrollOffset,
                            "scroll": c.scrollLeft(),
                            "size": s.x.size,
                            "visible": s.x.visible
                        });
                    }
                    s.x.isVisible && s.x.scroll.bar.css("left", c.scrollLeft() * s.x.kx + "px");
                    s.y.isVisible && s.y.scroll.bar.css("top", c.scrollTop() * s.y.kx + "px");
                });

                /* prevent native scrollbars to be visible on #anchor click */
                w.on("scroll" + namespace, function () {
                    w.scrollTop(0).scrollLeft(0);
                });

                if (o.disableBodyScroll) {
                    var handleMouseScroll = function (event) {
                        isVerticalScroll(event) ?
                            s.y.isVisible && s.y.mousewheel(event) :
                            s.x.isVisible && s.x.mousewheel(event);
                    };
                    w.on("MozMousePixelScroll" + namespace, handleMouseScroll);
                    w.on("mousewheel" + namespace, handleMouseScroll);

                    if (browser.mobile) {
                        w.on("touchstart" + namespace, function (event) {
                            var touch = event.originalEvent.touches && event.originalEvent.touches[0] || event;
                            var originalTouch = {
                                "pageX": touch.pageX,
                                "pageY": touch.pageY
                            };
                            var originalScroll = {
                                "left": c.scrollLeft(),
                                "top": c.scrollTop()
                            };
                            $(document).on("touchmove" + namespace, function (event) {
                                var touch = event.originalEvent.targetTouches && event.originalEvent.targetTouches[0] || event;
                                c.scrollLeft(originalScroll.left + originalTouch.pageX - touch.pageX);
                                c.scrollTop(originalScroll.top + originalTouch.pageY - touch.pageY);
                                event.preventDefault();
                            });
                            $(document).on("touchend" + namespace, function () {
                                $(document).off(namespace);
                            });
                        });
                    }
                }
                if ($.isFunction(o.onInit)){
                    o.onInit.apply(this, [c]);
                }
            } else {
                cw.css({
                    "height": "auto",
                    "margin-bottom": browser.scroll.height * -1 + "px",
                    "margin-right": browser.scroll.width * -1 + "px",
                    "max-height": ""
                });
            }

            // init scrollbars & recalculate sizes
            $.each(s, function (d, scrollx) {
                var scrollCallback = null;
                var scrollForward = 1;
                var scrollOffset = (d === "x") ? "scrollLeft" : "scrollTop";
                var scrollStep = o.scrollStep;
                var scrollTo = function () {
                    var currentOffset = c[scrollOffset]();
                    c[scrollOffset](currentOffset + scrollStep);
                    if (scrollForward == 1 && (currentOffset + scrollStep) >= scrollToValue)
                        currentOffset = c[scrollOffset]();
                    if (scrollForward == -1 && (currentOffset + scrollStep) <= scrollToValue)
                        currentOffset = c[scrollOffset]();
                    if (c[scrollOffset]() == currentOffset && scrollCallback) {
                        scrollCallback();
                    }
                }
                var scrollToValue = 0;

                if (!scrollx.scroll) {
                    scrollx.scroll = S._getScroll(o["scroll" + d]).addClass("scroll-" + d);

                    if(o.showArrows){
                        scrollx.scroll.addClass("scroll-element_arrows_visible");
                    }

                    scrollx.mousewheel = function (event) {
                        if (!scrollx.isVisible || (d === "x" && isVerticalScroll(event))) {
                            return true;
                        }
                        if (d === "y" && !isVerticalScroll(event)) {
                            s.x.mousewheel(event);
                            return true;
                        }

                        var delta = event.originalEvent.wheelDelta * -1 || event.originalEvent.detail;
                        var maxScrollValue = scrollx.size - scrollx.visible - scrollx.offset;

                        if ((delta > 0 && scrollToValue < maxScrollValue) || (delta < 0 && scrollToValue > 0)) {
                            scrollToValue = scrollToValue + delta;
                            if (scrollToValue < 0)
                                scrollToValue = 0;
                            if (scrollToValue > maxScrollValue)
                                scrollToValue = maxScrollValue;

                            S.scrollTo = S.scrollTo || {};
                            S.scrollTo[scrollOffset] = scrollToValue;
                            setTimeout(function () {
                                if (S.scrollTo) {
                                    c.stop().animate(S.scrollTo, 240, "linear", function () {
                                        scrollToValue = c[scrollOffset]();
                                    });
                                    S.scrollTo = null;
                                }
                            }, 1);
                        }

                        event.preventDefault();
                        return false;
                    };

                    scrollx.scroll
                        .on("MozMousePixelScroll" + namespace, scrollx.mousewheel)
                        .on("mousewheel" + namespace, scrollx.mousewheel)
                        .on("mouseenter" + namespace, function () {
                        scrollToValue = c[scrollOffset]();
                    });

                    // handle arrows & scroll inner mousedown event
                    scrollx.scroll.find(".scroll-arrow, .scroll-element_track")
                        .on("mousedown" + namespace, function (event) {
                        if (event.which != 1) // lmb
                            return true;

                        scrollForward = 1;

                        var data = {
                            "eventOffset": event[(d === "x") ? "pageX" : "pageY"],
                            "maxScrollValue": scrollx.size - scrollx.visible - scrollx.offset,
                            "scrollbarOffset": scrollx.scroll.bar.offset()[(d === "x") ? "left" : "top"],
                            "scrollbarSize": scrollx.scroll.bar[(d === "x") ? "outerWidth" : "outerHeight"]()
                        };
                        var timeout = 0, timer = 0;

                        if ($(this).hasClass("scroll-arrow")) {
                            scrollForward = $(this).hasClass("scroll-arrow_more") ? 1 : -1;
                            scrollStep = o.scrollStep * scrollForward;
                            scrollToValue = scrollForward > 0 ? data.maxScrollValue : 0;
                        } else {
                            scrollForward = (data.eventOffset > (data.scrollbarOffset + data.scrollbarSize) ? 1
                                : (data.eventOffset < data.scrollbarOffset ? -1 : 0));
                            scrollStep = Math.round(scrollx.visible * 0.75) * scrollForward;
                            scrollToValue = (data.eventOffset - data.scrollbarOffset -
                                (o.stepScrolling ? (scrollForward == 1 ? data.scrollbarSize : 0)
                                    : Math.round(data.scrollbarSize / 2)));
                            scrollToValue = c[scrollOffset]() + (scrollToValue / scrollx.kx);
                        }

                        S.scrollTo = S.scrollTo || {};
                        S.scrollTo[scrollOffset] = o.stepScrolling ? c[scrollOffset]() + scrollStep : scrollToValue;

                        if (o.stepScrolling) {
                            scrollCallback = function () {
                                scrollToValue = c[scrollOffset]();
                                clearInterval(timer);
                                clearTimeout(timeout);
                                timeout = 0;
                                timer = 0;
                            };
                            timeout = setTimeout(function () {
                                timer = setInterval(scrollTo, 40);
                            }, o.duration + 100);
                        }

                        setTimeout(function () {
                            if (S.scrollTo) {
                                c.animate(S.scrollTo, o.duration);
                                S.scrollTo = null;
                            }
                        }, 1);

                        return S._handleMouseDown(scrollCallback, event);
                    });

                    // handle scrollbar drag'n'drop
                    scrollx.scroll.bar.on("mousedown" + namespace, function (event) {
                        if (event.which != 1) // lmb
                            return true;

                        var eventPosition = event[(d === "x") ? "pageX" : "pageY"];
                        var initOffset = c[scrollOffset]();

                        scrollx.scroll.addClass("scroll-draggable");

                        $(document).on("mousemove" + namespace, function (event) {
                            var diff = parseInt((event[(d === "x") ? "pageX" : "pageY"] - eventPosition) / scrollx.kx, 10);
                            c[scrollOffset](initOffset + diff);
                        });

                        return S._handleMouseDown(function () {
                            scrollx.scroll.removeClass("scroll-draggable");
                            scrollToValue = c[scrollOffset]();
                        }, event);
                    });
                }
            });

            // remove classes & reset applied styles
            $.each(s, function (d, scrollx) {
                var scrollClass = "scroll-scroll" + d + "_visible";
                var scrolly = (d == "x") ? s.y : s.x;

                scrollx.scroll.removeClass(scrollClass);
                scrolly.scroll.removeClass(scrollClass);
                cw.removeClass(scrollClass);
            });

            // calculate init sizes
            $.each(s, function (d, scrollx) {
                $.extend(scrollx, (d == "x") ? {
                    "offset": parseInt(c.css("left"), 10) || 0,
                    "size": c.prop("scrollWidth"),
                    "visible": w.width()
                } : {
                    "offset": parseInt(c.css("top"), 10) || 0,
                    "size": c.prop("scrollHeight"),
                    "visible": w.height()
                });
            });

            // update scrollbar visibility/dimensions
            this._updateScroll("x", this.scrollx);
            this._updateScroll("y", this.scrolly);

            if ($.isFunction(o.onUpdate)){
                o.onUpdate.apply(this, [c]);
            }

            // calculate scroll size
            $.each(s, function (d, scrollx) {
                var cssOffset = (d === "x") ? "left" : "top";
                var cssFullSize = (d === "x") ? "outerWidth" : "outerHeight";
                var cssSize = (d === "x") ? "width" : "height";
                var offset = parseInt(c.css(cssOffset), 10) || 0;

                var AreaSize = scrollx.size;
                var AreaVisible = scrollx.visible + offset;

                var scrollSize = scrollx.scroll.size[cssFullSize]() + (parseInt(scrollx.scroll.size.css(cssOffset), 10) || 0);

                if (o.autoScrollSize) {
                    scrollx.scrollbarSize = parseInt(scrollSize * AreaVisible / AreaSize, 10);
                    scrollx.scroll.bar.css(cssSize, scrollx.scrollbarSize + "px");
                }

                scrollx.scrollbarSize = scrollx.scroll.bar[cssFullSize]();
                scrollx.kx = ((scrollSize - scrollx.scrollbarSize) / (AreaSize - AreaVisible)) || 1;
                scrollx.maxScrollOffset = AreaSize - AreaVisible;
            });

            c.scrollLeft(initScroll.scrollLeft).scrollTop(initScroll.scrollTop).trigger("scroll");
        },

        /**
         * Get scrollx/scrolly object
         *
         * @param {Mixed} scroll
         * @returns {jQuery} scroll object
         */
        _getScroll: function (scroll) {
            var types = {
                advanced: [
                    "<div class=\"scroll-element\">",
                    "<div class=\"scroll-element_corner\"></div>",
                    "<div class=\"scroll-arrow scroll-arrow_less\"></div>",
                    "<div class=\"scroll-arrow scroll-arrow_more\"></div>",
                    "<div class=\"scroll-element_outer\">",
                    "<div class=\"scroll-element_size\"></div>", // required! used for scrollbar size calculation !
                    "<div class=\"scroll-element_inner-wrapper\">",
                    "<div class=\"scroll-element_inner scroll-element_track\">", // used for handling scrollbar click
                    "<div class=\"scroll-element_inner-bottom\"></div>",
                    "</div>",
                    "</div>",
                    "<div class=\"scroll-bar\">", // required
                    "<div class=\"scroll-bar_body\">",
                    "<div class=\"scroll-bar_body-inner\"></div>",
                    "</div>",
                    "<div class=\"scroll-bar_bottom\"></div>",
                    "<div class=\"scroll-bar_center\"></div>",
                    "</div>",
                    "</div>",
                    "</div>"
                ].join(""),
                simple: [
                    "<div class=\"scroll-element\">",
                    "<div class=\"scroll-element_outer\">",
                    "<div class=\"scroll-element_size\"></div>", // required! used for scrollbar size calculation !
                    "<div class=\"scroll-element_track\"></div>", // used for handling scrollbar click
                    "<div class=\"scroll-bar\"></div>", // required
                    "</div>",
                    "</div>"
                ].join("")
            };
            if (types[scroll]) {
                scroll = types[scroll];
            }
            if (!scroll) {
                scroll = types["simple"];
            }
            if (typeof (scroll) == "string") {
                scroll = $(scroll).appendTo(this.wrapper);
            } else {
                scroll = $(scroll);
            }
            $.extend(scroll, {
                bar: scroll.find(".scroll-bar"),
                size: scroll.find(".scroll-element_size"),
                track: scroll.find(".scroll-element_track")
            });
            return scroll;
        },

        _handleMouseDown: function(callback, event) {
            var namespace = this.namespace;

            $(document).on("blur" + namespace, function () {
                $(document).add("body").off(namespace);
                callback && callback();
            });
            $(document).on("dragstart" + namespace, function (event) {
                event.preventDefault();
                return false;
            });
            $(document).on("mouseup" + namespace, function () {
                $(document).add("body").off(namespace);
                callback && callback();
            });
            $("body").on("selectstart" + namespace, function (event) {
                event.preventDefault();
                return false;
            });

            event && event.preventDefault();
            return false;
        },

        _updateScroll: function (d, scrollx) {
            var container = this.container,
                containerWrapper = this.containerWrapper || container,
                scrollClass = "scroll-scroll" + d + "_visible",
                scrolly = (d === "x") ? this.scrolly : this.scrollx,
                offset = parseInt(this.container.css((d === "x") ? "left" : "top"), 10) || 0,
                wrapper = this.wrapper;

            var AreaSize = scrollx.size;
            var AreaVisible = scrollx.visible + offset;

            // bug in IE9/11 with 1px diff
            scrollx.isVisible = (AreaSize - AreaVisible) > 1;
            if (scrollx.isVisible) {
                scrollx.scroll.addClass(scrollClass);
                scrolly.scroll.addClass(scrollClass);
                containerWrapper.addClass(scrollClass);
            } else {
                scrollx.scroll.removeClass(scrollClass);
                scrolly.scroll.removeClass(scrollClass);
                containerWrapper.removeClass(scrollClass);
            }

            if (d === "y") {
                if(container.is("textarea") || AreaSize < AreaVisible){
                    containerWrapper.css({
                        "height": (AreaVisible + browser.scroll.height) + "px",
                        "max-height": "none"
                    });
                } else {
                    containerWrapper.css({
                        //"height": "auto", // do not reset height value: issue with height:100%!
                        "max-height": (AreaVisible + browser.scroll.height) + "px"
                    });
                }
            }

            if (scrollx.size != container.prop("scrollWidth")
                || scrolly.size != container.prop("scrollHeight")
                || scrollx.visible != wrapper.width()
                || scrolly.visible != wrapper.height()
                || scrollx.offset != (parseInt(container.css("left"), 10) || 0)
                || scrolly.offset != (parseInt(container.css("top"), 10) || 0)
                ) {
                $.extend(this.scrollx, {
                    "offset": parseInt(container.css("left"), 10) || 0,
                    "size": container.prop("scrollWidth"),
                    "visible": wrapper.width()
                });
                $.extend(this.scrolly, {
                    "offset": parseInt(container.css("top"), 10) || 0,
                    "size": this.container.prop("scrollHeight"),
                    "visible": wrapper.height()
                });
                this._updateScroll(d === "x" ? "y" : "x", scrolly);
            }
        }
    };

    var CustomScrollbar = BaseScrollbar;

    /*
     * Extend jQuery as plugin
     *
     * @param {Mixed} command to execute
     * @param {Mixed} arguments as Array
     * @return {jQuery}
     */
    $.fn.scrollbar = function (command, args) {
        if (typeof command !== "string") {
            args = command;
            command = "init";
        }
        if (typeof args === "undefined") {
            args = [];
        }
        if (!$.isArray(args)) {
            args = [args];
        }
        this.not("body, .scroll-wrapper").each(function () {
            var element = $(this),
                instance = element.data(browser.data.name);
            if (instance || command === "init") {
                if (!instance) {
                    instance = new CustomScrollbar(element);
                }
                if (instance[command]) {
                    instance[command].apply(instance, args);
                }
            }
        });
        return this;
    };

    /**
     * Connect default options to global object
     */
    $.fn.scrollbar.options = defaults;


    /**
     * Check if scroll content/container size is changed
     */

    var updateScrollbars = (function () {
        var timer = 0,
            timerCounter = 0;

        return function (force) {
            var i, container, options, scroll, wrapper, scrollx, scrolly;
            for (i = 0; i < browser.scrolls.length; i++) {
                scroll = browser.scrolls[i];
                container = scroll.container;
                options = scroll.options;
                wrapper = scroll.wrapper;
                scrollx = scroll.scrollx;
                scrolly = scroll.scrolly;
                if (force || (options.autoUpdate && wrapper && wrapper.is(":visible") &&
                    (container.prop("scrollWidth") != scrollx.size || container.prop("scrollHeight") != scrolly.size || wrapper.width() != scrollx.visible || wrapper.height() != scrolly.visible))) {
                    scroll.init();

                    if (options.debug) {
                        window.console && console.log({
                            scrollHeight: container.prop("scrollHeight") + ":" + scroll.scrolly.size,
                            scrollWidth: container.prop("scrollWidth") + ":" + scroll.scrollx.size,
                            visibleHeight: wrapper.height() + ":" + scroll.scrolly.visible,
                            visibleWidth: wrapper.width() + ":" + scroll.scrollx.visible
                        }, true);
                        timerCounter++;
                    }
                }
            }
            if (debug && timerCounter > 10) {
                window.console && console.log("Scroll updates exceed 10");
                updateScrollbars = function () {};
            } else {
                clearTimeout(timer);
                timer = setTimeout(updateScrollbars, 300);
            }
        };
    })();

    /* ADDITIONAL FUNCTIONS */
    /**
     * Get native browser scrollbar size (height/width)
     *
     * @param {Boolean} actual size or CSS size, default - CSS size
     * @returns {Object} with height, width
     */
    function getBrowserScrollSize(actualSize) {
        if (browser.webkit && !actualSize) {
            return {
                "height": 0,
                "width": 0
            };
        }

        if (!browser.data.outer) {
            var css = {
                "border": "none",
                "box-sizing": "content-box",
                "height": "200px",
                "margin": "0",
                "padding": "0",
                "width": "200px"
            };
            browser.data.inner = $("<div>").css($.extend({}, css));
            browser.data.outer = $("<div>").css($.extend({
                "left": "-1000px",
                "overflow": "scroll",
                "position": "absolute",
                "top": "-1000px"
            }, css)).append(browser.data.inner).appendTo("body");
        }

        browser.data.outer.scrollLeft(1000).scrollTop(1000);

        return {
            "height": Math.ceil((browser.data.outer.offset().top - browser.data.inner.offset().top) || 0),
            "width": Math.ceil((browser.data.outer.offset().left - browser.data.inner.offset().left) || 0)
        };
    }

    /**
     * Check if native browser scrollbars overlay content
     *
     * @returns {Boolean}
     */
    function isScrollOverlaysContent() {
        var scrollSize = getBrowserScrollSize(true);
        return !(scrollSize.height || scrollSize.width);
    }

    function isVerticalScroll(event) {
        var e = event.originalEvent;
        if (e.axis && e.axis === e.HORIZONTAL_AXIS)
            return false;
        if (e.wheelDeltaX)
            return false;
        return true;
    }


    /**
     * Extend AngularJS as UI directive
     * and expose a provider for override default config
     *
     */
    if (window.angular) {
        (function (angular) {
            angular.module("jQueryScrollbar", [])
                .provider("jQueryScrollbar", function () {
                var defaultOptions = defaults;
                return {
                    setOptions: function (options) {
                        angular.extend(defaultOptions, options);
                    },
                    $get: function () {
                        return {
                            options: angular.copy(defaultOptions)
                        };
                    }
                };
            })
                .directive("jqueryScrollbar", function (jQueryScrollbar, $parse) {
                return {
                    "restrict": "AC",
                    "link": function (scope, element, attrs) {
                        var model = $parse(attrs.jqueryScrollbar),
                            options = model(scope);
                        element.scrollbar(options || jQueryScrollbar.options)
                            .on("$destroy", function () {
                            element.scrollbar("destroy");
                        });
                    }
                };
            });
        })(window.angular);
    }
}));
var $__Object$defineProperties = Object.defineProperties;

var copyrightOverlayHelper = function() {
    "use strict";

    function copyrightOverlayHelper(config) {
        var Services = new app.services(),
            templates = Services.templateService.templates;

        this.Helpers = new app.helpers();
        this.config = config;

        this.Templates = {
            _info: templates("helper.copyright-overlay._info")
        }

        setTimeout(function() {
            this.pagetools = Services.pagetools;
            this.init();
        }.bind(this));
    }

    $__Object$defineProperties(copyrightOverlayHelper.prototype, {
        init: {
            value: function() {
                var infoTemplate = this.Templates._info({});

                this.config.scope.append(infoTemplate);

                setTimeout(function() {
                    this.config.scope.find(".scrollbar-inner").scrollbar();
                    this.$popup = this.config.scope.find(".helper-copyright-overlay");
                }.bind(this));

                this.config.scope.find(".helper-copyright-overlay .close-btn").on("click touchend", function(ev) {
                    ev.preventDefault();
                    this.config.scope.find(".helper-copyright-overlay").hide();
                    this.config.scope.find(".info-btn").show();
                    return false;
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        updateInfoText: {
            value: function(infoText) {
                this.$popup.find(".text-area .inner").empty();
                this.$popup.find(".text-area .inner").append(infoText);
                var isiPad = navigator.userAgent.match(/iPad/i) != null;
                if(this.pagetools.window._element[0].innerWidth < 768 || isiPad && this.pagetools.window._element[0].innerWidth < 1024){
                    this.buildOverlay(infoText);
                }
                else{
                    this.$popup.show();
                    this.config.scope.find(".info-btn").hide();
                }
            },

            enumerable: false,
            writable: true
        },

        buildOverlay: {
            value: function(infoText) {
                this.overlayConfig = {
                    moduleClass: "module-carousel info",
                    afterInit: function (element) {
                        if (element) {
                            var $element = $(element);
                            $element.append("<div class=\"infoText\">"+infoText+"</div>");
                            $element.find("iframe").show();
                        }
                    }.bind(this),
                    afterClose: function() {
                        console.log("overlay has closed!!!");

                        setTimeout(function() {
                            this.pagetools.body._element[0].scrollTop = this.pagetools.window._element[0].document.documentElement.scrollTop = 0;
                        }.bind(this),500);
                    }.bind(this)
                };

                new this.Helpers["overlay"](this.overlayConfig);
            },

            enumerable: false,
            writable: true
        }
    });

    return copyrightOverlayHelper;
}();

return copyrightOverlayHelper;
});
}).apply(window);/**!!<[helper.copyright-overlay]!!**/
/**!![helper.date-picker]>!!**/
(function(){
registerHelper("date-picker", function(application) {
/* =========================================================
 * bootstrap-datepicker.js
 * Repo: https://github.com/eternicode/bootstrap-datepicker/
 * Demo: http://eternicode.github.io/bootstrap-datepicker/
 * Docs: http://bootstrap-datepicker.readthedocs.org/
 * Forked from http://www.eyecon.ro/bootstrap-datepicker
 * =========================================================
 * Started by Stefan Petre; improvements by Andrew Rowls + contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================= */

(function($, undefined){
    function UTCDate(){
        return new Date(Date.UTC.apply(Date, arguments));
    }
    function UTCToday(){
        var today = new Date();
        return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
    }
    function isUTCEquals(date1, date2) {
        return (
            date1.getUTCFullYear() === date2.getUTCFullYear() &&
            date1.getUTCMonth() === date2.getUTCMonth() &&
            date1.getUTCDate() === date2.getUTCDate()
        );
    }
    function alias(method){
        return function(){
            return this[method].apply(this, arguments);
        };
    }

    var DateArray = (function(){
        var extras = {
            get: function(i){
                return this.slice(i)[0];
            },
            contains: function(d){
                // Array.indexOf is not cross-browser;
                // $.inArray doesn't work with Dates
                var val = d && d.valueOf();
                for (var i=0, l=this.length; i < l; i++)
                    if (this[i].valueOf() === val)
                        return i;
                return -1;
            },
            remove: function(i){
                this.splice(i,1);
            },
            replace: function(new_array){
                if (!new_array)
                    return;
                if (!$.isArray(new_array))
                    new_array = [new_array];
                this.clear();
                this.push.apply(this, new_array);
            },
            clear: function(){
                this.length = 0;
            },
            copy: function(){
                var a = new DateArray();
                a.replace(this);
                return a;
            }
        };

        return function(){
            var a = [];
            a.push.apply(a, arguments);
            $.extend(a, extras);
            return a;
        };
    })();


    // Picker object

    var Datepicker = function(element, options){
        this._process_options(options);

        this.dates = new DateArray();
        this.viewDate = this.o.defaultViewDate;
        this.focusDate = null;

        this.element = $(element);
        this.isInline = false;
        this.isInput = this.element.is("input");
        this.component = this.element.hasClass("date") ? this.element.find(".add-on, .input-group-addon, .btn") : false;
        this.hasInput = this.component && this.element.find("input").length;
        if (this.component && this.component.length === 0)
            this.component = false;

        this.picker = $(DPGlobal.template);
        this._buildEvents();
        this._attachEvents();

        if (this.isInline){
            this.picker.addClass("datepicker-inline").appendTo(this.element);
        }
        else {
            this.picker.addClass("datepicker-dropdown dropdown-menu");
        }

        if (this.o.rtl){
            this.picker.addClass("datepicker-rtl");
        }

        this.viewMode = this.o.startView;

        if (this.o.calendarWeeks)
            this.picker.find("tfoot .today, tfoot .clear")
                        .attr("colspan", function(i, val){
                return parseInt(val) + 1;
            });

        this._allow_update = false;

        this.setStartDate(this._o.startDate);
        this.setEndDate(this._o.endDate);
        this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
        this.setDatesDisabled(this.o.datesDisabled);

        this.fillDow();
        this.fillMonths();

        this._allow_update = true;

        this.update();
        this.showMode();

        if (this.isInline){
            this.show();
        }
    };

    Datepicker.prototype = {
        constructor: Datepicker,

        _process_options: function(opts){
            // Store raw options for reference
            this._o = $.extend({}, this._o, opts);
            // Processed options
            var o = this.o = $.extend({}, this._o);

            // Check if "de-DE" style date is available, if not language should
            // fallback to 2 letter code eg "de"
            var lang = o.language;
            if (!dates[lang]){
                lang = lang.split("-")[0];
                if (!dates[lang])
                    lang = defaults.language;
            }
            o.language = lang;

            switch (o.startView){
                case 2:
                case "decade":
                    o.startView = 2;
                    break;
                case 1:
                case "year":
                    o.startView = 1;
                    break;
                default:
                    o.startView = 0;
            }

            switch (o.minViewMode){
                case 1:
                case "months":
                    o.minViewMode = 1;
                    break;
                case 2:
                case "years":
                    o.minViewMode = 2;
                    break;
                default:
                    o.minViewMode = 0;
            }

            o.startView = Math.max(o.startView, o.minViewMode);

            // true, false, or Number > 0
            if (o.multidate !== true){
                o.multidate = Number(o.multidate) || false;
                if (o.multidate !== false)
                    o.multidate = Math.max(0, o.multidate);
            }
            o.multidateSeparator = String(o.multidateSeparator);

            o.weekStart %= 7;
            o.weekEnd = ((o.weekStart + 6) % 7);

            var format = DPGlobal.parseFormat(o.format);
            if (o.startDate !== -Infinity){
                if (!!o.startDate){
                    if (o.startDate instanceof Date)
                        o.startDate = this._local_to_utc(this._zero_time(o.startDate));
                    else
                        o.startDate = DPGlobal.parseDate(o.startDate, format, o.language);
                }
                else {
                    o.startDate = -Infinity;
                }
            }
            if (o.endDate !== Infinity){
                if (!!o.endDate){
                    if (o.endDate instanceof Date)
                        o.endDate = this._local_to_utc(this._zero_time(o.endDate));
                    else
                        o.endDate = DPGlobal.parseDate(o.endDate, format, o.language);
                }
                else {
                    o.endDate = Infinity;
                }
            }

            o.daysOfWeekDisabled = o.daysOfWeekDisabled||[];
            if (!$.isArray(o.daysOfWeekDisabled))
                o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/);
            o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function(d){
                return parseInt(d, 10);
            });

            o.datesDisabled = o.datesDisabled||[];
            if (!$.isArray(o.datesDisabled)) {
                var datesDisabled = [];
                datesDisabled.push(DPGlobal.parseDate(o.datesDisabled, format, o.language));
                o.datesDisabled = datesDisabled;
            }
            o.datesDisabled = $.map(o.datesDisabled,function(d){
                return DPGlobal.parseDate(d, format, o.language);
            });

            var plc = String(o.orientation).toLowerCase().split(/\s+/g),
                _plc = o.orientation.toLowerCase();
            plc = $.grep(plc, function(word){
                return /^auto|left|right|top|bottom$/.test(word);
            });
            o.orientation = {x: "auto", y: "auto"};
            if (!_plc || _plc === "auto")
                ; // no action
            else if (plc.length === 1){
                switch (plc[0]){
                    case "top":
                    case "bottom":
                        o.orientation.y = plc[0];
                        break;
                    case "left":
                    case "right":
                        o.orientation.x = plc[0];
                        break;
                }
            }
            else {
                _plc = $.grep(plc, function(word){
                    return /^left|right$/.test(word);
                });
                o.orientation.x = _plc[0] || "auto";

                _plc = $.grep(plc, function(word){
                    return /^top|bottom$/.test(word);
                });
                o.orientation.y = _plc[0] || "auto";
            }
            if (o.defaultViewDate) {
                var year = o.defaultViewDate.year || new Date().getFullYear();
                var month = o.defaultViewDate.month || 0;
                var day = o.defaultViewDate.day || 1;
                o.defaultViewDate = UTCDate(year, month, day);
            } else {
                o.defaultViewDate = UTCToday();
            }
            o.showOnFocus = o.showOnFocus !== undefined ? o.showOnFocus : true;
        },
        _events: [],
        _secondaryEvents: [],
        _applyEvents: function(evs){
            for (var i=0, el, ch, ev; i < evs.length; i++){
                el = evs[i][0];
                if (evs[i].length === 2){
                    ch = undefined;
                    ev = evs[i][1];
                }
                else if (evs[i].length === 3){
                    ch = evs[i][1];
                    ev = evs[i][2];
                }
                el.on(ev, ch);
            }
        },
        _unapplyEvents: function(evs){
            for (var i=0, el, ev, ch; i < evs.length; i++){
                el = evs[i][0];
                if (evs[i].length === 2){
                    ch = undefined;
                    ev = evs[i][1];
                }
                else if (evs[i].length === 3){
                    ch = evs[i][1];
                    ev = evs[i][2];
                }
                el.off(ev, ch);
            }
        },
        _buildEvents: function(){
            var events = {
                keyup: $.proxy(function(e){
                    if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
                        this.update();
                }, this),
                keydown: $.proxy(this.keydown, this)
            };

            if (this.o.showOnFocus === true) {
                events.focus = $.proxy(this.show, this);
            }

            if (this.isInput) {
                // single input
                this._events = [
                    [this.element, events]
                ];
            }
            else if (this.component && this.hasInput) {
                // component: input + button
                this._events = [
                    // For components that are not readonly, allow keyboard nav
                    [this.element.find("input"), events],
                    [this.component, {
                        click: $.proxy(this.show, this)
                    }]
                ];
            }
            else if (this.element.is("div")){
                // inline datepicker
                this.isInline = true;
            }
            else {
                this._events = [
                    [this.element, {
                        click: $.proxy(this.show, this)
                    }]
                ];
            }
            this._events.push(
                // Component: listen for blur on element descendants
                [this.element, "*", {
                    blur: $.proxy(function(e){
                        this._focused_from = e.target;
                    }, this)
                }],
                // Input: listen for blur on element
                [this.element, {
                    blur: $.proxy(function(e){
                        this._focused_from = e.target;
                    }, this)
                }]
            );

            this._secondaryEvents = [
                [this.picker, {
                    click: $.proxy(this.click, this)
                }],
                [$(window), {
                    resize: $.proxy(this.place, this)
                }],
                [$(document), {
                    "mousedown touchstart": $.proxy(function(e){
                        // Clicked outside the datepicker, hide it
                        if (!(
                            (this.element.is(e.target) ||
                            this.element.find(e.target).length ||
                            this.picker.is(e.target) || this.picker.find(e.target).length)
                        )){
                            this.hide();
                        }
                    }, this)
                }]
            ];
        },
        _attachEvents: function(){
            this._detachEvents();
            this._applyEvents(this._events);
        },
        _detachEvents: function(){
            this._unapplyEvents(this._events);
        },
        _attachSecondaryEvents: function(){
            this._detachSecondaryEvents();
            this._applyEvents(this._secondaryEvents);
        },
        _detachSecondaryEvents: function(){
            this._unapplyEvents(this._secondaryEvents);
        },
        _trigger: function(event, altdate){
            var date = altdate || this.dates.get(-1),
                local_date = this._utc_to_local(date);

            this.element.trigger({
                type: event,
                date: local_date,
                dates: $.map(this.dates, this._utc_to_local),
                format: $.proxy(function(ix, format){
                    if (arguments.length === 0){
                        ix = this.dates.length - 1;
                        format = this.o.format;
                    }
                    else if (typeof ix === "string"){
                        format = ix;
                        ix = this.dates.length - 1;
                    }
                    format = format || this.o.format;
                    var date = this.dates.get(ix);
                    return DPGlobal.formatDate(date, format, this.o.language);
                }, this)
            });
        },

        show: function(){
            if (this.element.attr("readonly"))
                return;
            if (!this.isInline)
                this.picker.appendTo(this.o.container);
            this.place();
            this.picker.show();
            this._attachSecondaryEvents();
            this._trigger("show");
            if ((window.navigator.msMaxTouchPoints || "ontouchstart" in document) && this.o.disableTouchKeyboard) {
                $(this.element).blur();
            }
            return this;
        },

        hide: function(){
            if (this.isInline)
                return this;
            if (!this.picker.is(":visible"))
                return this;
            this.focusDate = null;
            this.picker.hide().detach();
            this._detachSecondaryEvents();
            this.viewMode = this.o.startView;
            this.showMode();

            if (
                this.o.forceParse &&
                (
                    (this.isInput && this.element.val() || this.hasInput && this.element.find("input").val())
                )
            )
                this.setValue();
            this._trigger("hide");
            return this;
        },

        remove: function(){
            this.hide();
            this._detachEvents();
            this._detachSecondaryEvents();
            this.picker.remove();
            delete this.element.data().datepicker;
            if (!this.isInput){
                delete this.element.data().date;
            }
            return this;
        },

        _utc_to_local: function(utc){
            return utc && new Date(utc.getTime() + (utc.getTimezoneOffset()*60000));
        },
        _local_to_utc: function(local){
            return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
        },
        _zero_time: function(local){
            return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
        },
        _zero_utc_time: function(utc){
            return utc && new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate()));
        },

        getDates: function(){
            return $.map(this.dates, this._utc_to_local);
        },

        getUTCDates: function(){
            return $.map(this.dates, function(d){
                return new Date(d);
            });
        },

        getDate: function(){
            return this._utc_to_local(this.getUTCDate());
        },

        getUTCDate: function(){
            var selected_date = this.dates.get(-1);
            if (typeof selected_date !== "undefined") {
                return new Date(selected_date);
            } else {
                return null;
            }
        },

        clearDates: function(){
            var element;
            if (this.isInput) {
                element = this.element;
            } else if (this.component) {
                element = this.element.find("input");
            }

            if (element) {
                element.val("").change();
            }

            this.update();
            this._trigger("changeDate");

            if (this.o.autoclose) {
                this.hide();
            }
        },
        setDates: function(){
            var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
            this.update.apply(this, args);
            this._trigger("changeDate");
            this.setValue();
            return this;
        },

        setUTCDates: function(){
            var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
            this.update.apply(this, $.map(args, this._utc_to_local));
            this._trigger("changeDate");
            this.setValue();
            return this;
        },

        setDate: alias("setDates"),
        setUTCDate: alias("setUTCDates"),

        setValue: function(){
            var formatted = this.getFormattedDate();
            if (!this.isInput){
                if (this.component){
                    this.element.find("input").val(formatted).change();
                }
            }
            else {
                this.element.val(formatted).change();
            }
            return this;
        },

        getFormattedDate: function(format){
            if (format === undefined)
                format = this.o.format;

            var lang = this.o.language;
            return $.map(this.dates, function(d){
                return DPGlobal.formatDate(d, format, lang);
            }).join(this.o.multidateSeparator);
        },

        setStartDate: function(startDate){
            this._process_options({startDate: startDate});
            this.update();
            this.updateNavArrows();
            return this;
        },

        setEndDate: function(endDate){
            this._process_options({endDate: endDate});
            this.update();
            this.updateNavArrows();
            return this;
        },

        setDaysOfWeekDisabled: function(daysOfWeekDisabled){
            this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
            this.update();
            this.updateNavArrows();
            return this;
        },

        setDatesDisabled: function(datesDisabled){
            this._process_options({datesDisabled: datesDisabled});
            this.update();
            this.updateNavArrows();
        },

        place: function(){
            if (this.isInline)
                return this;
            var calendarWidth = this.picker.outerWidth(),
                calendarHeight = this.picker.outerHeight(),
                visualPadding = 10,
                windowWidth = $(this.o.container).width(),
                windowHeight = $(this.o.container).height(),
                scrollTop = $(this.o.container).scrollTop(),
                appendOffset = $(this.o.container).offset();

            var parentsZindex = [];
            this.element.parents().each(function(){
                var itemZIndex = $(this).css("z-index");
                if (itemZIndex !== "auto" && itemZIndex !== 0) parentsZindex.push(parseInt(itemZIndex));
            });
            var zIndex = Math.max.apply(Math, parentsZindex) + 10;
            var offset = this.component ? this.component.parent().offset() : this.element.offset();
            var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
            var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
            var left = offset.left - appendOffset.left,
                top = offset.top - appendOffset.top;

            this.picker.removeClass(
                "datepicker-orient-top datepicker-orient-bottom "+
                "datepicker-orient-right datepicker-orient-left"
            );

            if (this.o.orientation.x !== "auto"){
                this.picker.addClass("datepicker-orient-" + this.o.orientation.x);
                if (this.o.orientation.x === "right")
                    left -= calendarWidth - width;
            }
            // auto x orientation is best-placement: if it crosses a window
            // edge, fudge it sideways
            else {
                if (offset.left < 0) {
                    // component is outside the window on the left side. Move it into visible range
                    this.picker.addClass("datepicker-orient-left");
                    left -= offset.left - visualPadding;
                } else if (left + calendarWidth > windowWidth) {
                    // the calendar passes the widow right edge. Align it to component right side
                    this.picker.addClass("datepicker-orient-right");
                    left = offset.left + width - calendarWidth;
                } else {
                    // Default to left
                    this.picker.addClass("datepicker-orient-left");
                }
            }

            // auto y orientation is best-situation: top or bottom, no fudging,
            // decision based on which shows more of the calendar
            var yorient = this.o.orientation.y,
                top_overflow, bottom_overflow;
            if (yorient === "auto"){
                top_overflow = -scrollTop + top - calendarHeight;
                bottom_overflow = scrollTop + windowHeight - (top + height + calendarHeight);
                if (Math.max(top_overflow, bottom_overflow) === bottom_overflow)
                    yorient = "top";
                else
                    yorient = "bottom";
            }
            this.picker.addClass("datepicker-orient-" + yorient);
            if (yorient === "top")
                top += height;
            else
                top -= calendarHeight + parseInt(this.picker.css("padding-top"));

            if (this.o.rtl) {
                var right = windowWidth - (left + width);
                this.picker.css({
                    top: top,
                    right: right,
                    zIndex: zIndex
                });
            } else {
                this.picker.css({
                    top: top,
                    left: left,
                    zIndex: zIndex
                });
            }
            return this;
        },

        _allow_update: true,
        update: function(){
            if (!this._allow_update)
                return this;

            var oldDates = this.dates.copy(),
                dates = [],
                fromArgs = false;
            if (arguments.length){
                $.each(arguments, $.proxy(function(i, date){
                    if (date instanceof Date)
                        date = this._local_to_utc(date);
                    dates.push(date);
                }, this));
                fromArgs = true;
            }
            else {
                dates = this.isInput
                        ? this.element.val()
                        : this.element.data("date") || this.element.find("input").val();
                if (dates && this.o.multidate)
                    dates = dates.split(this.o.multidateSeparator);
                else
                    dates = [dates];
                delete this.element.data().date;
            }

            dates = $.map(dates, $.proxy(function(date){
                return DPGlobal.parseDate(date, this.o.format, this.o.language);
            }, this));
            dates = $.grep(dates, $.proxy(function(date){
                return (
                    date < this.o.startDate ||
                    date > this.o.endDate ||
                    !date
                );
            }, this), true);
            this.dates.replace(dates);

            if (this.dates.length)
                this.viewDate = new Date(this.dates.get(-1));
            else if (this.viewDate < this.o.startDate)
                this.viewDate = new Date(this.o.startDate);
            else if (this.viewDate > this.o.endDate)
                this.viewDate = new Date(this.o.endDate);

            if (fromArgs){
                // setting date by clicking
                this.setValue();
            }
            else if (dates.length){
                // setting date by typing
                if (String(oldDates) !== String(this.dates))
                    this._trigger("changeDate");
            }
            if (!this.dates.length && oldDates.length)
                this._trigger("clearDate");

            this.fill();
            return this;
        },

        fillDow: function(){
            var dowCnt = this.o.weekStart,
                html = "<tr>";
            if (this.o.calendarWeeks){
                this.picker.find(".datepicker-days thead tr:first-child .datepicker-switch")
                    .attr("colspan", function(i, val){
                    return parseInt(val) + 1;
                });
                var cell = "<th class=\"cw\">&#160;</th>";
                html += cell;
            }
            while (dowCnt < this.o.weekStart + 7){
                html += "<th class=\"dow\">"+dates[this.o.language].daysMin[(dowCnt++)%7]+"</th>";
            }
            html += "</tr>";
            this.picker.find(".datepicker-days thead").append(html);
        },

        fillMonths: function(){
            var html = "",
            i = 0;
            while (i < 12){
                html += "<span class=\"month\">"+dates[this.o.language].monthsShort[i++]+"</span>";
            }
            this.picker.find(".datepicker-months td").html(html);
        },

        setRange: function(range){
            if (!range || !range.length)
                delete this.range;
            else
                this.range = $.map(range, function(d){
                    return d.valueOf();
                });
            this.fill();
        },

        getClassNames: function(date){
            var cls = [],
                year = this.viewDate.getUTCFullYear(),
                month = this.viewDate.getUTCMonth(),
                today = new Date();
            if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
                cls.push("old");
            }
            else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
                cls.push("new");
            }
            if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
                cls.push("focused");
            // Compare internal UTC date with local today, not UTC today
            if (this.o.todayHighlight &&
                date.getUTCFullYear() === today.getFullYear() &&
                date.getUTCMonth() === today.getMonth() &&
                date.getUTCDate() === today.getDate()){
                cls.push("today");
            }
            if (this.dates.contains(date) !== -1)
                cls.push("active");
            if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate ||
                $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1){
                cls.push("disabled");
            }
            if (this.o.datesDisabled.length > 0 &&
                $.grep(this.o.datesDisabled, function(d){
                    return isUTCEquals(date, d);
                }).length > 0) {
                cls.push("disabled", "disabled-date");
            }

            if (this.range){
                if (date > this.range[0] && date < this.range[this.range.length-1]){
                    cls.push("range");
                }
                if ($.inArray(date.valueOf(), this.range) !== -1){
                    cls.push("selected");
                }
            }
            return cls;
        },

        fill: function(){
            var d = new Date(this.viewDate),
                year = d.getUTCFullYear(),
                month = d.getUTCMonth(),
                startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
                startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
                endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
                endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
                todaytxt = dates[this.o.language].today || dates["en"].today || "",
                cleartxt = dates[this.o.language].clear || dates["en"].clear || "",
                tooltip;
            if (isNaN(year) || isNaN(month))
                return;
            this.picker.find(".datepicker-days thead .datepicker-switch")
                        .text(dates[this.o.language].months[month]+" "+year);
            this.picker.find("tfoot .today")
                        .text(todaytxt)
                        .toggle(this.o.todayBtn !== false);
            this.picker.find("tfoot .clear")
                        .text(cleartxt)
                        .toggle(this.o.clearBtn !== false);
            this.updateNavArrows();
            this.fillMonths();
            var prevMonth = UTCDate(year, month-1, 28),
                day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
            prevMonth.setUTCDate(day);
            prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
            var nextMonth = new Date(prevMonth);
            nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
            nextMonth = nextMonth.valueOf();
            var html = [];
            var clsName;
            while (prevMonth.valueOf() < nextMonth){
                if (prevMonth.getUTCDay() === this.o.weekStart){
                    html.push("<tr>");
                    if (this.o.calendarWeeks){
                        // ISO 8601: First week contains first thursday.
                        // ISO also states week starts on Monday, but we can be more abstract here.
                        var
                            // Start of current week: based on weekstart/current date
                            ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 86400000),
                            // Thursday of this week
                            th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 86400000),
                            // First Thursday of year, year from thursday
                            yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*86400000),
                            // Calendar week: ms between thursdays, div ms per day, div 7 days
                            calWeek =  (th - yth) / 86400000 / 7 + 1;
                        html.push("<td class=\"cw\">"+ calWeek +"</td>");
                    }
                }
                clsName = this.getClassNames(prevMonth);
                clsName.push("day");

                if (this.o.beforeShowDay !== $.noop){
                    var before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
                    if (before === undefined)
                        before = {};
                    else if (typeof(before) === "boolean")
                        before = {enabled: before};
                    else if (typeof(before) === "string")
                        before = {classes: before};
                    if (before.enabled === false)
                        clsName.push("disabled");
                    if (before.classes)
                        clsName = clsName.concat(before.classes.split(/\s+/));
                    if (before.tooltip)
                        tooltip = before.tooltip;
                }

                clsName = $.unique(clsName);
                html.push("<td class=\""+clsName.join(" ")+"\"" + (tooltip ? " title=\""+tooltip+"\"" : "") + ">"+prevMonth.getUTCDate() + "</td>");
                tooltip = null;
                if (prevMonth.getUTCDay() === this.o.weekEnd){
                    html.push("</tr>");
                }
                prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
            }
            this.picker.find(".datepicker-days tbody").empty().append(html.join(""));

            var months = this.picker.find(".datepicker-months")
                        .find("th:eq(1)")
                            .text(year)
                            .end()
                        .find("span").removeClass("active");

            $.each(this.dates, function(i, d){
                if (d.getUTCFullYear() === year)
                    months.eq(d.getUTCMonth()).addClass("active");
            });

            if (year < startYear || year > endYear){
                months.addClass("disabled");
            }
            if (year === startYear){
                months.slice(0, startMonth).addClass("disabled");
            }
            if (year === endYear){
                months.slice(endMonth+1).addClass("disabled");
            }

            if (this.o.beforeShowMonth !== $.noop){
                var that = this;
                $.each(months, function(i, month){
                    if (!$(month).hasClass("disabled")) {
                        var moDate = new Date(year, i, 1);
                        var before = that.o.beforeShowMonth(moDate);
                        if (before === false)
                            $(month).addClass("disabled");
                    }
                });
            }

            html = "";
            year = parseInt(year/10, 10) * 10;
            var yearCont = this.picker.find(".datepicker-years")
                                .find("th:eq(1)")
                                    .text(year + "-" + (year + 9))
                                    .end()
                                .find("td");
            year -= 1;
            var years = $.map(this.dates, function(d){
                return d.getUTCFullYear();
            }),
                classes;
            for (var i = -1; i < 11; i++){
                classes = ["year"];
                if (i === -1)
                    classes.push("old");
                else if (i === 10)
                    classes.push("new");
                if ($.inArray(year, years) !== -1)
                    classes.push("active");
                if (year < startYear || year > endYear)
                    classes.push("disabled");
                html += "<span class=\"" + classes.join(" ") + "\">" + year + "</span>";
                year += 1;
            }
            yearCont.html(html);
        },

        updateNavArrows: function(){
            if (!this._allow_update)
                return;

            var d = new Date(this.viewDate),
                year = d.getUTCFullYear(),
                month = d.getUTCMonth();
            switch (this.viewMode){
                case 0:
                    if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()){
                        this.picker.find(".prev").css({visibility: "hidden"});
                    }
                    else {
                        this.picker.find(".prev").css({visibility: "visible"});
                    }
                    if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()){
                        this.picker.find(".next").css({visibility: "hidden"});
                    }
                    else {
                        this.picker.find(".next").css({visibility: "visible"});
                    }
                    break;
                case 1:
                case 2:
                    if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()){
                        this.picker.find(".prev").css({visibility: "hidden"});
                    }
                    else {
                        this.picker.find(".prev").css({visibility: "visible"});
                    }
                    if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()){
                        this.picker.find(".next").css({visibility: "hidden"});
                    }
                    else {
                        this.picker.find(".next").css({visibility: "visible"});
                    }
                    break;
            }
        },

        click: function(e){
            e.preventDefault();
            var target = $(e.target).closest("span, td, th"),
                year, month, day;
            if (target.length === 1){
                switch (target[0].nodeName.toLowerCase()){
                    case "th":
                        switch (target[0].className){
                            case "datepicker-switch":
                                this.showMode(1);
                                break;
                            case "prev":
                            case "next":
                                var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className === "prev" ? -1 : 1);
                                switch (this.viewMode){
                                    case 0:
                                        this.viewDate = this.moveMonth(this.viewDate, dir);
                                        this._trigger("changeMonth", this.viewDate);
                                        break;
                                    case 1:
                                    case 2:
                                        this.viewDate = this.moveYear(this.viewDate, dir);
                                        if (this.viewMode === 1)
                                            this._trigger("changeYear", this.viewDate);
                                        break;
                                }
                                this.fill();
                                break;
                            case "today":
                                var date = new Date();
                                date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);

                                this.showMode(-2);
                                var which = this.o.todayBtn === "linked" ? null : "view";
                                this._setDate(date, which);
                                break;
                            case "clear":
                                this.clearDates();
                                break;
                        }
                        break;
                    case "span":
                        if (!target.hasClass("disabled")){
                            this.viewDate.setUTCDate(1);
                            if (target.hasClass("month")){
                                day = 1;
                                month = target.parent().find("span").index(target);
                                year = this.viewDate.getUTCFullYear();
                                this.viewDate.setUTCMonth(month);
                                this._trigger("changeMonth", this.viewDate);
                                if (this.o.minViewMode === 1){
                                    this._setDate(UTCDate(year, month, day));
                                }
                            }
                            else {
                                day = 1;
                                month = 0;
                                year = parseInt(target.text(), 10)||0;
                                this.viewDate.setUTCFullYear(year);
                                this._trigger("changeYear", this.viewDate);
                                if (this.o.minViewMode === 2){
                                    this._setDate(UTCDate(year, month, day));
                                }
                            }
                            this.showMode(-1);
                            this.fill();
                        }
                        break;
                    case "td":
                        if (target.hasClass("day") && !target.hasClass("disabled")){
                            day = parseInt(target.text(), 10)||1;
                            year = this.viewDate.getUTCFullYear();
                            month = this.viewDate.getUTCMonth();
                            if (target.hasClass("old")){
                                if (month === 0){
                                    month = 11;
                                    year -= 1;
                                }
                                else {
                                    month -= 1;
                                }
                            }
                            else if (target.hasClass("new")){
                                if (month === 11){
                                    month = 0;
                                    year += 1;
                                }
                                else {
                                    month += 1;
                                }
                            }
                            this._setDate(UTCDate(year, month, day));
                        }
                        break;
                }
            }
            if (this.picker.is(":visible") && this._focused_from){
                $(this._focused_from).focus();
            }
            delete this._focused_from;
        },

        _toggle_multidate: function(date){
            var ix = this.dates.contains(date);
            if (!date){
                this.dates.clear();
            }

            if (ix !== -1){
                if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive){
                    this.dates.remove(ix);
                }
            } else if (this.o.multidate === false) {
                this.dates.clear();
                this.dates.push(date);
            }
            else {
                this.dates.push(date);
            }

            if (typeof this.o.multidate === "number")
                while (this.dates.length > this.o.multidate)
                    this.dates.remove(0);
        },

        _setDate: function(date, which){
            if (!which || which === "date")
                this._toggle_multidate(date && new Date(date));
            if (!which || which  === "view")
                this.viewDate = date && new Date(date);

            this.fill();
            this.setValue();
            if (!which || which  !== "view") {
                this._trigger("changeDate");
            }
            var element;
            if (this.isInput){
                element = this.element;
            }
            else if (this.component){
                element = this.element.find("input");
            }
            if (element){
                element.change();
            }
            if (this.o.autoclose && (!which || which === "date")){
                this.hide();
            }
        },

        moveMonth: function(date, dir){
            if (!date)
                return undefined;
            if (!dir)
                return date;
            var new_date = new Date(date.valueOf()),
                day = new_date.getUTCDate(),
                month = new_date.getUTCMonth(),
                mag = Math.abs(dir),
                new_month, test;
            dir = dir > 0 ? 1 : -1;
            if (mag === 1){
                test = dir === -1
                    // If going back one month, make sure month is not current month
                    // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
                    ? function(){
                    return new_date.getUTCMonth() === month;
                }
                    // If going forward one month, make sure month is as expected
                    // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
                    : function(){
                    return new_date.getUTCMonth() !== new_month;
                };
                new_month = month + dir;
                new_date.setUTCMonth(new_month);
                // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
                if (new_month < 0 || new_month > 11)
                    new_month = (new_month + 12) % 12;
            }
            else {
                // For magnitudes >1, move one month at a time...
                for (var i=0; i < mag; i++)
                    // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
                    new_date = this.moveMonth(new_date, dir);
                // ...then reset the day, keeping it in the new month
                new_month = new_date.getUTCMonth();
                new_date.setUTCDate(day);
                test = function(){
                    return new_month !== new_date.getUTCMonth();
                };
            }
            // Common date-resetting loop -- if date is beyond end of month, make it
            // end of month
            while (test()){
                new_date.setUTCDate(--day);
                new_date.setUTCMonth(new_month);
            }
            return new_date;
        },

        moveYear: function(date, dir){
            return this.moveMonth(date, dir*12);
        },

        dateWithinRange: function(date){
            return date >= this.o.startDate && date <= this.o.endDate;
        },

        keydown: function(e){
            if (!this.picker.is(":visible")){
                if (e.keyCode === 27) // allow escape to hide and re-show picker
                    this.show();
                return;
            }
            var dateChanged = false,
                dir, newDate, newViewDate,
                focusDate = this.focusDate || this.viewDate;
            switch (e.keyCode){
                case 27: // escape
                    if (this.focusDate){
                        this.focusDate = null;
                        this.viewDate = this.dates.get(-1) || this.viewDate;
                        this.fill();
                    }
                    else
                        this.hide();
                    e.preventDefault();
                    break;
                case 37: // left
                case 39: // right
                    if (!this.o.keyboardNavigation)
                        break;
                    dir = e.keyCode === 37 ? -1 : 1;
                    if (e.ctrlKey){
                        newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
                        newViewDate = this.moveYear(focusDate, dir);
                        this._trigger("changeYear", this.viewDate);
                    }
                    else if (e.shiftKey){
                        newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
                        newViewDate = this.moveMonth(focusDate, dir);
                        this._trigger("changeMonth", this.viewDate);
                    }
                    else {
                        newDate = new Date(this.dates.get(-1) || UTCToday());
                        newDate.setUTCDate(newDate.getUTCDate() + dir);
                        newViewDate = new Date(focusDate);
                        newViewDate.setUTCDate(focusDate.getUTCDate() + dir);
                    }
                    if (this.dateWithinRange(newViewDate)){
                        this.focusDate = this.viewDate = newViewDate;
                        this.setValue();
                        this.fill();
                        e.preventDefault();
                    }
                    break;
                case 38: // up
                case 40: // down
                    if (!this.o.keyboardNavigation)
                        break;
                    dir = e.keyCode === 38 ? -1 : 1;
                    if (e.ctrlKey){
                        newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
                        newViewDate = this.moveYear(focusDate, dir);
                        this._trigger("changeYear", this.viewDate);
                    }
                    else if (e.shiftKey){
                        newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
                        newViewDate = this.moveMonth(focusDate, dir);
                        this._trigger("changeMonth", this.viewDate);
                    }
                    else {
                        newDate = new Date(this.dates.get(-1) || UTCToday());
                        newDate.setUTCDate(newDate.getUTCDate() + dir * 7);
                        newViewDate = new Date(focusDate);
                        newViewDate.setUTCDate(focusDate.getUTCDate() + dir * 7);
                    }
                    if (this.dateWithinRange(newViewDate)){
                        this.focusDate = this.viewDate = newViewDate;
                        this.setValue();
                        this.fill();
                        e.preventDefault();
                    }
                    break;
                case 32: // spacebar
                    // Spacebar is used in manually typing dates in some formats.
                    // As such, its behavior should not be hijacked.
                    break;
                case 13: // enter
                    focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
                    if (this.o.keyboardNavigation) {
                        this._toggle_multidate(focusDate);
                        dateChanged = true;
                    }
                    this.focusDate = null;
                    this.viewDate = this.dates.get(-1) || this.viewDate;
                    this.setValue();
                    this.fill();
                    if (this.picker.is(":visible")){
                        e.preventDefault();
                        if (typeof e.stopPropagation === "function") {
                            // All modern browsers, IE9+
                            e.stopPropagation();
                        } else {
                            // IE6,7,8 ignore "stopPropagation"
                            e.cancelBubble = true;
                        }
                        if (this.o.autoclose)
                            this.hide();
                    }
                    break;
                case 9: // tab
                    this.focusDate = null;
                    this.viewDate = this.dates.get(-1) || this.viewDate;
                    this.fill();
                    this.hide();
                    break;
            }
            if (dateChanged){
                if (this.dates.length)
                    this._trigger("changeDate");
                else
                    this._trigger("clearDate");
                var element;
                if (this.isInput){
                    element = this.element;
                }
                else if (this.component){
                    element = this.element.find("input");
                }
                if (element){
                    element.change();
                }
            }
        },

        showMode: function(dir){
            if (dir){
                this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir));
            }
            this.picker
                .children("div")
                .hide()
                .filter(".datepicker-" + DPGlobal.modes[this.viewMode].clsName)
                    .css("display", "block");
            this.updateNavArrows();
        }
    };

    var DateRangePicker = function(element, options){
        this.element = $(element);
        this.inputs = $.map(options.inputs, function(i){
            return i.jquery ? i[0] : i;
        });
        delete options.inputs;

        datepickerPlugin.call($(this.inputs), options)
            .bind("changeDate", $.proxy(this.dateUpdated, this));

        this.pickers = $.map(this.inputs, function(i){
            return $(i).data("datepicker");
        });
        this.updateDates();
    };
    DateRangePicker.prototype = {
        updateDates: function(){
            this.dates = $.map(this.pickers, function(i){
                return i.getUTCDate();
            });
            this.updateRanges();
        },
        updateRanges: function(){
            var range = $.map(this.dates, function(d){
                return d.valueOf();
            });
            $.each(this.pickers, function(i, p){
                p.setRange(range);
            });
        },
        dateUpdated: function(e){
            // `this.updating` is a workaround for preventing infinite recursion
            // between `changeDate` triggering and `setUTCDate` calling.  Until
            // there is a better mechanism.
            if (this.updating)
                return;
            this.updating = true;

            var dp = $(e.target).data("datepicker"),
                new_date = dp.getUTCDate(),
                i = $.inArray(e.target, this.inputs),
                j = i - 1,
                k = i + 1,
                l = this.inputs.length;
            if (i === -1)
                return;

            $.each(this.pickers, function(i, p){
                if (!p.getUTCDate())
                    p.setUTCDate(new_date);
            });

            if (new_date < this.dates[j]){
                // Date being moved earlier/left
                while (j >= 0 && new_date < this.dates[j]){
                    this.pickers[j--].setUTCDate(new_date);
                }
            }
            else if (new_date > this.dates[k]){
                // Date being moved later/right
                while (k < l && new_date > this.dates[k]){
                    this.pickers[k++].setUTCDate(new_date);
                }
            }
            this.updateDates();

            delete this.updating;
        },
        remove: function(){
            $.map(this.pickers, function(p){
                p.remove();
            });
            delete this.element.data().datepicker;
        }
    };

    function opts_from_el(el, prefix){
        // Derive options from element data-attrs
        var data = $(el).data(),
            out = {}, inkey,
            replace = new RegExp("^" + prefix.toLowerCase() + "([A-Z])");
        prefix = new RegExp("^" + prefix.toLowerCase());
        function re_lower(_,a){
            return a.toLowerCase();
        }
        for (var key in data)
            if (prefix.test(key)){
                inkey = key.replace(replace, re_lower);
                out[inkey] = data[key];
            }
        return out;
    }

    function opts_from_locale(lang){
        // Derive options from locale plugins
        var out = {};
        // Check if "de-DE" style date is available, if not language should
        // fallback to 2 letter code eg "de"
        if (!dates[lang]){
            lang = lang.split("-")[0];
            if (!dates[lang])
                return;
        }
        var d = dates[lang];
        $.each(locale_opts, function(i,k){
            if (k in d)
                out[k] = d[k];
        });
        return out;
    }

    var old = $.fn.datepicker;
    var datepickerPlugin = function(option){
        var args = Array.apply(null, arguments);
        args.shift();
        var internal_return;
        this.each(function(){
            var $this = $(this),
                data = $this.data("datepicker"),
                options = typeof option === "object" && option;
            if (!data){
                var elopts = opts_from_el(this, "date"),
                    // Preliminary otions
                    xopts = $.extend({}, defaults, elopts, options),
                    locopts = opts_from_locale(xopts.language),
                    // Options priority: js args, data-attrs, locales, defaults
                    opts = $.extend({}, defaults, locopts, elopts, options);
                if ($this.hasClass("input-daterange") || opts.inputs){
                    var ropts = {
                        inputs: opts.inputs || $this.find("input").toArray()
                    };
                    $this.data("datepicker", (data = new DateRangePicker(this, $.extend(opts, ropts))));
                }
                else {
                    $this.data("datepicker", (data = new Datepicker(this, opts)));
                }
            }
            if (typeof option === "string" && typeof data[option] === "function"){
                internal_return = data[option].apply(data, args);
                if (internal_return !== undefined)
                    return false;
            }
        });
        if (internal_return !== undefined)
            return internal_return;
        else
            return this;
    };
    $.fn.datepicker = datepickerPlugin;

    var defaults = $.fn.datepicker.defaults = {
        autoclose: false,
        beforeShowDay: $.noop,
        beforeShowMonth: $.noop,
        calendarWeeks: false,
        clearBtn: false,
        toggleActive: false,
        daysOfWeekDisabled: [],
        datesDisabled: [],
        endDate: Infinity,
        forceParse: true,
        format: "mm/dd/yyyy",
        keyboardNavigation: true,
        language: "en",
        minViewMode: 0,
        multidate: false,
        multidateSeparator: ",",
        orientation: "auto",
        rtl: false,
        startDate: -Infinity,
        startView: 0,
        todayBtn: false,
        todayHighlight: false,
        weekStart: 0,
        disableTouchKeyboard: false,
        container: "body"
    };
    var locale_opts = $.fn.datepicker.locale_opts = [
        "format",
        "rtl",
        "weekStart"
    ];
    $.fn.datepicker.Constructor = Datepicker;
    var dates = $.fn.datepicker.dates = {
        en: {
            days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
            daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
            daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
            months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
            monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
            today: "Today",
            clear: "Clear"
        }
    };

    var DPGlobal = {
        modes: [
            {
                clsName: "days",
                navFnc: "Month",
                navStep: 1
            },
            {
                clsName: "months",
                navFnc: "FullYear",
                navStep: 1
            },
            {
                clsName: "years",
                navFnc: "FullYear",
                navStep: 10
        }],
        isLeapYear: function(year){
            return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
        },
        getDaysInMonth: function(year, month){
            return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
        },
        validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
        nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
        parseFormat: function(format){
            // IE treats \0 as a string end in inputs (truncating the value),
            // so it's a bad format delimiter, anyway
            var separators = format.replace(this.validParts, "\u0000").split("\u0000"),
                parts = format.match(this.validParts);
            if (!separators || !separators.length || !parts || parts.length === 0){
                throw new Error("Invalid date format.");
            }
            return {separators: separators, parts: parts};
        },
        parseDate: function(date, format, language){
            if (!date)
                return undefined;
            if (date instanceof Date)
                return date;
            if (typeof format === "string")
                format = DPGlobal.parseFormat(format);
            var part_re = /([\-+]\d+)([dmwy])/,
                parts = date.match(/([\-+]\d+)([dmwy])/g),
                part, dir, i;
            if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){
                date = new Date();
                for (i=0; i < parts.length; i++){
                    part = part_re.exec(parts[i]);
                    dir = parseInt(part[1]);
                    switch (part[2]){
                        case "d":
                            date.setUTCDate(date.getUTCDate() + dir);
                            break;
                        case "m":
                            date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
                            break;
                        case "w":
                            date.setUTCDate(date.getUTCDate() + dir * 7);
                            break;
                        case "y":
                            date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
                            break;
                    }
                }
                return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);
            }
            parts = date && date.match(this.nonpunctuation) || [];
            date = new Date();
            var parsed = {},
                setters_order = ["yyyy", "yy", "M", "MM", "m", "mm", "d", "dd"],
                setters_map = {
                    yyyy: function(d,v){
                        return d.setUTCFullYear(v);
                    },
                    yy: function(d,v){
                        return d.setUTCFullYear(2000+v);
                    },
                    m: function(d,v){
                        if (isNaN(d))
                            return d;
                        v -= 1;
                        while (v < 0) v += 12;
                        v %= 12;
                        d.setUTCMonth(v);
                        while (d.getUTCMonth() !== v)
                            d.setUTCDate(d.getUTCDate()-1);
                        return d;
                    },
                    d: function(d,v){
                        return d.setUTCDate(v);
                    }
                },
                val, filtered;
            setters_map["M"] = setters_map["MM"] = setters_map["mm"] = setters_map["m"];
            setters_map["dd"] = setters_map["d"];
            date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
            var fparts = format.parts.slice();
            // Remove noop parts
            if (parts.length !== fparts.length){
                fparts = $(fparts).filter(function(i,p){
                    return $.inArray(p, setters_order) !== -1;
                }).toArray();
            }
            // Process remainder
            function match_part(){
                var m = this.slice(0, parts[i].length),
                    p = parts[i].slice(0, m.length);
                return m.toLowerCase() === p.toLowerCase();
            }
            if (parts.length === fparts.length){
                var cnt;
                for (i=0, cnt = fparts.length; i < cnt; i++){
                    val = parseInt(parts[i], 10);
                    part = fparts[i];
                    if (isNaN(val)){
                        switch (part){
                            case "MM":
                                filtered = $(dates[language].months).filter(match_part);
                                val = $.inArray(filtered[0], dates[language].months) + 1;
                                break;
                            case "M":
                                filtered = $(dates[language].monthsShort).filter(match_part);
                                val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
                                break;
                        }
                    }
                    parsed[part] = val;
                }
                var _date, s;
                for (i=0; i < setters_order.length; i++){
                    s = setters_order[i];
                    if (s in parsed && !isNaN(parsed[s])){
                        _date = new Date(date);
                        setters_map[s](_date, parsed[s]);
                        if (!isNaN(_date))
                            date = _date;
                    }
                }
            }
            return date;
        },
        formatDate: function(date, format, language){
            if (!date)
                return "";
            if (typeof format === "string")
                format = DPGlobal.parseFormat(format);
            var val = {
                d: date.getUTCDate(),
                D: dates[language].daysShort[date.getUTCDay()],
                DD: dates[language].days[date.getUTCDay()],
                m: date.getUTCMonth() + 1,
                M: dates[language].monthsShort[date.getUTCMonth()],
                MM: dates[language].months[date.getUTCMonth()],
                yy: date.getUTCFullYear().toString().substring(2),
                yyyy: date.getUTCFullYear()
            };
            val.dd = (val.d < 10 ? "0" : "") + val.d;
            val.mm = (val.m < 10 ? "0" : "") + val.m;
            date = [];
            var seps = $.extend([], format.separators);
            for (var i=0, cnt = format.parts.length; i <= cnt; i++){
                if (seps.length)
                    date.push(seps.shift());
                date.push(val[format.parts[i]]);
            }
            return date.join("");
        },
        headTemplate: "<thead>"+
                            "<tr>"+
                                "<th class=\"prev\"></th>"+
                                "<th colspan=\"5\" class=\"datepicker-switch\"></th>"+
                                "<th class=\"next\"></th>"+
                            "</tr>"+
                        "</thead>",
        contTemplate: "<tbody><tr><td colspan=\"7\"></td></tr></tbody>",
        footTemplate: "<tfoot>"+
                            "<tr>"+
                                "<th colspan=\"7\" class=\"today\"></th>"+
                            "</tr>"+
                            "<tr>"+
                                "<th colspan=\"7\" class=\"clear\"></th>"+
                            "</tr>"+
                        "</tfoot>"
    };
    DPGlobal.template = "<div class=\"datepicker\">"+
                            "<div class=\"datepicker-days\">"+
                                "<table class=\" table-condensed\">"+
                                    DPGlobal.headTemplate+
                                    "<tbody></tbody>"+
                                    DPGlobal.footTemplate+
                                "</table>"+
                            "</div>"+
                            "<div class=\"datepicker-months\">"+
                                "<table class=\"table-condensed\">"+
                                    DPGlobal.headTemplate+
                                    DPGlobal.contTemplate+
                                    DPGlobal.footTemplate+
                                "</table>"+
                            "</div>"+
                            "<div class=\"datepicker-years\">"+
                                "<table class=\"table-condensed\">"+
                                    DPGlobal.headTemplate+
                                    DPGlobal.contTemplate+
                                    DPGlobal.footTemplate+
                                "</table>"+
                            "</div>"+
                        "</div>";

    $.fn.datepicker.DPGlobal = DPGlobal;

    // Localisation
    // Canadian English
    $.fn.datepicker.dates["en-ca"] = {
        days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
        daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
        daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
        months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
        monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
        today: "Today",
        clear: "Clear",
        weekStart: 1,
        format: "dd/mm/yyyy"
    };
    // Canadian French
    $.fn.datepicker.dates["fr-ca"] = {
        days: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
        daysShort: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
        daysMin: ["d", "l", "ma", "me", "j", "v", "s"],
        months: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
        monthsShort: ["janv.", "févr.", "mars", "avril", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."],
        today: "Aujourd'hui",
        clear: "Effacer",
        weekStart: 1,
        format: "dd/mm/yyyy"
    };


    /*
        /* DATEPICKER NO CONFLICT
        * =================== *

        $.fn.datepicker.noConflict = function(){
            $.fn.datepicker = old;
            return this;
        };


        /* DATEPICKER DATA-API
        * ================== *

        $(document).on(
            'focus.datepicker.data-api click.datepicker.data-api',
            '[data-provide="datepicker"]',
            function(e){
                var $this = $(this);
                if ($this.data('datepicker'))
                    return;
                e.preventDefault();
                // component click requires us to explicitly show it
                datepickerPlugin.call($this, 'show');
            }
        );
        $(function(){
            datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
        });
    */;
}(window.jQuery));
var $__Object$defineProperties = Object.defineProperties;

var MDPDatePicker = function() {
    "use strict";

    function MDPDatePicker(config) {
        var defaultConfig = {
            scope: null,
            pickerConfig: {
                language: this.getCultureCode()
            }
        }

        this.config = $.extend(true, defaultConfig, config);

        this.$scope = this.config.scope;

        this.picker=null;

        this.init();
    }

    $__Object$defineProperties(MDPDatePicker.prototype, {
        init: {
            value: function() {
                this.picker = this.$scope.datepicker(this.config.pickerConfig);
            },

            enumerable: false,
            writable: true
        },

        getCultureCode: {
            value: function() {
                var cultureCode = "en-gb";
                if($("body").data("culture-code").length) {
                    cultureCode = $("body").data("culture-code").toLowerCase();
                }
                return cultureCode;
            },

            enumerable: false,
            writable: true
        },

        destroy: {
            value: function() {
                this.$scope.datepicker("remove");
            },

            enumerable: false,
            writable: true
        }
    });

    return MDPDatePicker;
}();

return MDPDatePicker;
});
}).apply(window);/**!!<[helper.date-picker]!!**/
/**!![helper.date-time]>!!**/
(function(){
registerHelper("date-time", function(application) {
//! moment.js
//! version : 2.10.2
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
//! license : MIT
//! momentjs.com

(function (global, factory) {
    typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() :
    typeof define === "function" && define.amd ? define(factory) :
    global.moment = factory();
}(this, function () {
    "use strict";

    var hookCallback;

    function utils_hooks__hooks () {
        return hookCallback.apply(null, arguments);
    }

    // This is done to register the method called with moment()
    // without creating circular dependencies.
    function setHookCallback (callback) {
        hookCallback = callback;
    }

    function defaultParsingFlags() {
        // We need to deep clone this object.
        return {
            empty: false,
            unusedTokens: [],
            unusedInput: [],
            overflow: -2,
            charsLeftOver: 0,
            nullInput: false,
            invalidMonth: null,
            invalidFormat: false,
            userInvalidated: false,
            iso: false
        };
    }

    function isArray(input) {
        return Object.prototype.toString.call(input) === "[object Array]";
    }

    function isDate(input) {
        return Object.prototype.toString.call(input) === "[object Date]" || input instanceof Date;
    }

    function map(arr, fn) {
        var res = [], i;
        for (i = 0; i < arr.length; ++i) {
            res.push(fn(arr[i], i));
        }
        return res;
    }

    function hasOwnProp(a, b) {
        return Object.prototype.hasOwnProperty.call(a, b);
    }

    function extend(a, b) {
        for (var i in b) {
            if (hasOwnProp(b, i)) {
                a[i] = b[i];
            }
        }

        if (hasOwnProp(b, "toString")) {
            a.toString = b.toString;
        }

        if (hasOwnProp(b, "valueOf")) {
            a.valueOf = b.valueOf;
        }

        return a;
    }

    function create_utc__createUTC (input, format, locale, strict) {
        return createLocalOrUTC(input, format, locale, strict, true).utc();
    }

    function valid__isValid(m) {
        if (m._isValid == null) {
            m._isValid = !isNaN(m._d.getTime()) &&
                m._pf.overflow < 0 &&
                !m._pf.empty &&
                !m._pf.invalidMonth &&
                !m._pf.nullInput &&
                !m._pf.invalidFormat &&
                !m._pf.userInvalidated;

            if (m._strict) {
                m._isValid = m._isValid &&
                    m._pf.charsLeftOver === 0 &&
                    m._pf.unusedTokens.length === 0 &&
                    m._pf.bigHour === undefined;
            }
        }
        return m._isValid;
    }

    function valid__createInvalid (flags) {
        var m = create_utc__createUTC(NaN);
        if (flags != null) {
            extend(m._pf, flags);
        }
        else {
            m._pf.userInvalidated = true;
        }

        return m;
    }

    var momentProperties = utils_hooks__hooks.momentProperties = [];

    function copyConfig(to, from) {
        var i, prop, val;

        if (typeof from._isAMomentObject !== "undefined") {
            to._isAMomentObject = from._isAMomentObject;
        }
        if (typeof from._i !== "undefined") {
            to._i = from._i;
        }
        if (typeof from._f !== "undefined") {
            to._f = from._f;
        }
        if (typeof from._l !== "undefined") {
            to._l = from._l;
        }
        if (typeof from._strict !== "undefined") {
            to._strict = from._strict;
        }
        if (typeof from._tzm !== "undefined") {
            to._tzm = from._tzm;
        }
        if (typeof from._isUTC !== "undefined") {
            to._isUTC = from._isUTC;
        }
        if (typeof from._offset !== "undefined") {
            to._offset = from._offset;
        }
        if (typeof from._pf !== "undefined") {
            to._pf = from._pf;
        }
        if (typeof from._locale !== "undefined") {
            to._locale = from._locale;
        }

        if (momentProperties.length > 0) {
            for (i in momentProperties) {
                prop = momentProperties[i];
                val = from[prop];
                if (typeof val !== "undefined") {
                    to[prop] = val;
                }
            }
        }

        return to;
    }

    var updateInProgress = false;

    // Moment prototype object
    function Moment(config) {
        copyConfig(this, config);
        this._d = new Date(+config._d);
        // Prevent infinite loop in case updateOffset creates new moment
        // objects.
        if (updateInProgress === false) {
            updateInProgress = true;
            utils_hooks__hooks.updateOffset(this);
            updateInProgress = false;
        }
    }

    function isMoment (obj) {
        return obj instanceof Moment || (obj != null && hasOwnProp(obj, "_isAMomentObject"));
    }

    function toInt(argumentForCoercion) {
        var coercedNumber = +argumentForCoercion,
            value = 0;

        if (coercedNumber !== 0 && isFinite(coercedNumber)) {
            if (coercedNumber >= 0) {
                value = Math.floor(coercedNumber);
            } else {
                value = Math.ceil(coercedNumber);
            }
        }

        return value;
    }

    function compareArrays(array1, array2, dontConvert) {
        var len = Math.min(array1.length, array2.length),
            lengthDiff = Math.abs(array1.length - array2.length),
            diffs = 0,
            i;
        for (i = 0; i < len; i++) {
            if ((dontConvert && array1[i] !== array2[i]) ||
                (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
                diffs++;
            }
        }
        return diffs + lengthDiff;
    }

    function Locale() {}

    var locales = {};
    var globalLocale;

    function normalizeLocale(key) {
        return key ? key.toLowerCase().replace("_", "-") : key;
    }

    // pick the locale from the array
    // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
    // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
    function chooseLocale(names) {
        var i = 0, j, next, locale, split;

        while (i < names.length) {
            split = normalizeLocale(names[i]).split("-");
            j = split.length;
            next = normalizeLocale(names[i + 1]);
            next = next ? next.split("-") : null;
            while (j > 0) {
                locale = loadLocale(split.slice(0, j).join("-"));
                if (locale) {
                    return locale;
                }
                if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
                    //the next array item is better than a shallower substring of this one
                    break;
                }
                j--;
            }
            i++;
        }
        return null;
    }

    function loadLocale(name) {
        var oldLocale = null;
        // TODO: Find a better way to register and load all the locales in Node
        if (!locales[name] && typeof module !== "undefined" &&
                module && module.exports) {
            try {
                oldLocale = globalLocale._abbr;
                require("./locale/" + name);
                // because defineLocale currently also sets the global locale, we
                // want to undo that for lazy loaded locales
                locale_locales__getSetGlobalLocale(oldLocale);
            } catch (e) {}
        }
        return locales[name];
    }

    // This function will load locale and then set the global locale.  If
    // no arguments are passed in, it will simply return the current global
    // locale key.
    function locale_locales__getSetGlobalLocale (key, values) {
        var data;
        if (key) {
            if (typeof values === "undefined") {
                data = locale_locales__getLocale(key);
            }
            else {
                data = defineLocale(key, values);
            }

            if (data) {
                // moment.duration._locale = moment._locale = data;
                globalLocale = data;
            }
        }

        return globalLocale._abbr;
    }

    function defineLocale (name, values) {
        if (values !== null) {
            values.abbr = name;
            if (!locales[name]) {
                locales[name] = new Locale();
            }
            locales[name].set(values);

            // backwards compat for now: also set the locale
            locale_locales__getSetGlobalLocale(name);

            return locales[name];
        } else {
            // useful for testing
            delete locales[name];
            return null;
        }
    }

    // returns locale data
    function locale_locales__getLocale (key) {
        var locale;

        if (key && key._locale && key._locale._abbr) {
            key = key._locale._abbr;
        }

        if (!key) {
            return globalLocale;
        }

        if (!isArray(key)) {
            //short-circuit everything else
            locale = loadLocale(key);
            if (locale) {
                return locale;
            }
            key = [key];
        }

        return chooseLocale(key);
    }

    var aliases = {};

    function addUnitAlias (unit, shorthand) {
        var lowerCase = unit.toLowerCase();
        aliases[lowerCase] = aliases[lowerCase + "s"] = aliases[shorthand] = unit;
    }

    function normalizeUnits(units) {
        return typeof units === "string" ? aliases[units] || aliases[units.toLowerCase()] : undefined;
    }

    function normalizeObjectUnits(inputObject) {
        var normalizedInput = {},
            normalizedProp,
            prop;

        for (prop in inputObject) {
            if (hasOwnProp(inputObject, prop)) {
                normalizedProp = normalizeUnits(prop);
                if (normalizedProp) {
                    normalizedInput[normalizedProp] = inputObject[prop];
                }
            }
        }

        return normalizedInput;
    }

    function makeGetSet (unit, keepTime) {
        return function (value) {
            if (value != null) {
                get_set__set(this, unit, value);
                utils_hooks__hooks.updateOffset(this, keepTime);
                return this;
            } else {
                return get_set__get(this, unit);
            }
        };
    }

    function get_set__get (mom, unit) {
        return mom._d["get" + (mom._isUTC ? "UTC" : "") + unit]();
    }

    function get_set__set (mom, unit, value) {
        return mom._d["set" + (mom._isUTC ? "UTC" : "") + unit](value);
    }

    // MOMENTS

    function getSet (units, value) {
        var unit;
        if (typeof units === "object") {
            for (unit in units) {
                this.set(unit, units[unit]);
            }
        } else {
            units = normalizeUnits(units);
            if (typeof this[units] === "function") {
                return this[units](value);
            }
        }
        return this;
    }

    function zeroFill(number, targetLength, forceSign) {
        var output = "" + Math.abs(number),
            sign = number >= 0;

        while (output.length < targetLength) {
            output = "0" + output;
        }
        return (sign ? (forceSign ? "+" : "") : "-") + output;
    }

    var formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g;

    var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;

    var formatFunctions = {};

    var formatTokenFunctions = {};

    // token:    'M'
    // padded:   ['MM', 2]
    // ordinal:  'Mo'
    // callback: function () { this.month() + 1 }
    function addFormatToken (token, padded, ordinal, callback) {
        var func = callback;
        if (typeof callback === "string") {
            func = function () {
                return this[callback]();
            };
        }
        if (token) {
            formatTokenFunctions[token] = func;
        }
        if (padded) {
            formatTokenFunctions[padded[0]] = function () {
                return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
            };
        }
        if (ordinal) {
            formatTokenFunctions[ordinal] = function () {
                return this.localeData().ordinal(func.apply(this, arguments), token);
            };
        }
    }

    function removeFormattingTokens(input) {
        if (input.match(/\[[\s\S]/)) {
            return input.replace(/^\[|\]$/g, "");
        }
        return input.replace(/\\/g, "");
    }

    function makeFormatFunction(format) {
        var array = format.match(formattingTokens), i, length;

        for (i = 0, length = array.length; i < length; i++) {
            if (formatTokenFunctions[array[i]]) {
                array[i] = formatTokenFunctions[array[i]];
            } else {
                array[i] = removeFormattingTokens(array[i]);
            }
        }

        return function (mom) {
            var output = "";
            for (i = 0; i < length; i++) {
                output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
            }
            return output;
        };
    }

    // format date using native date object
    function formatMoment(m, format) {
        if (!m.isValid()) {
            return m.localeData().invalidDate();
        }

        format = expandFormat(format, m.localeData());

        if (!formatFunctions[format]) {
            formatFunctions[format] = makeFormatFunction(format);
        }

        return formatFunctions[format](m);
    }

    function expandFormat(format, locale) {
        var i = 5;

        function replaceLongDateFormatTokens(input) {
            return locale.longDateFormat(input) || input;
        }

        localFormattingTokens.lastIndex = 0;
        while (i >= 0 && localFormattingTokens.test(format)) {
            format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
            localFormattingTokens.lastIndex = 0;
            i -= 1;
        }

        return format;
    }

    //       0 - 9
    var match1         = /\d/;
    //      00 - 99
    var match2         = /\d\d/;
    //     000 - 999
    var match3         = /\d{3}/;
    //    0000 - 9999
    var match4         = /\d{4}/;
    // -999999 - 999999
    var match6         = /[+-]?\d{6}/;
    //       0 - 99
    var match1to2      = /\d\d?/;
    //       0 - 999
    var match1to3      = /\d{1,3}/;
    //       0 - 9999
    var match1to4      = /\d{1,4}/;
    // -999999 - 999999
    var match1to6      = /[+-]?\d{1,6}/;

    //       0 - inf
    var matchUnsigned  = /\d+/;
    //    -inf - inf
    var matchSigned    = /[+-]?\d+/;

    // +00:00 -00:00 +0000 -0000 or Z
    var matchOffset    = /Z|[+-]\d\d:?\d\d/gi;

    // 123456789 123456789.123
    var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/;

    // any word (or two) characters or numbers including two/three word month in arabic.
    var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;

    var regexes = {};

    function addRegexToken (token, regex, strictRegex) {
        regexes[token] = typeof regex === "function" ? regex : function (isStrict) {
            return (isStrict && strictRegex) ? strictRegex : regex;
        };
    }

    function getParseRegexForToken (token, config) {
        if (!hasOwnProp(regexes, token)) {
            return new RegExp(unescapeFormat(token));
        }

        return regexes[token](config._strict, config._locale);
    }

    // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
    function unescapeFormat(s) {
        return s.replace("\\", "").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
            return p1 || p2 || p3 || p4;
        }).replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
    }

    var tokens = {};

    function addParseToken (token, callback) {
        var i, func = callback;
        if (typeof token === "string") {
            token = [token];
        }
        if (typeof callback === "number") {
            func = function (input, array) {
                array[callback] = toInt(input);
            };
        }
        for (i = 0; i < token.length; i++) {
            tokens[token[i]] = func;
        }
    }

    function addWeekParseToken (token, callback) {
        addParseToken(token, function (input, array, config, token) {
            config._w = config._w || {};
            callback(input, config._w, config, token);
        });
    }

    function addTimeToArrayFromToken(token, input, config) {
        if (input != null && hasOwnProp(tokens, token)) {
            tokens[token](input, config._a, config, token);
        }
    }

    var YEAR = 0;
    var MONTH = 1;
    var DATE = 2;
    var HOUR = 3;
    var MINUTE = 4;
    var SECOND = 5;
    var MILLISECOND = 6;

    function daysInMonth(year, month) {
        return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
    }

    // FORMATTING

    addFormatToken("M", ["MM", 2], "Mo", function () {
        return this.month() + 1;
    });

    addFormatToken("MMM", 0, 0, function (format) {
        return this.localeData().monthsShort(this, format);
    });

    addFormatToken("MMMM", 0, 0, function (format) {
        return this.localeData().months(this, format);
    });

    // ALIASES

    addUnitAlias("month", "M");

    // PARSING

    addRegexToken("M",    match1to2);
    addRegexToken("MM",   match1to2, match2);
    addRegexToken("MMM",  matchWord);
    addRegexToken("MMMM", matchWord);

    addParseToken(["M", "MM"], function (input, array) {
        array[MONTH] = toInt(input) - 1;
    });

    addParseToken(["MMM", "MMMM"], function (input, array, config, token) {
        var month = config._locale.monthsParse(input, token, config._strict);
        // if we didn't find a month name, mark the date as invalid.
        if (month != null) {
            array[MONTH] = month;
        } else {
            config._pf.invalidMonth = input;
        }
    });

    // LOCALES

    var defaultLocaleMonths = "January_February_March_April_May_June_July_August_September_October_November_December".split("_");
    function localeMonths (m) {
        return this._months[m.month()];
    }

    var defaultLocaleMonthsShort = "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_");
    function localeMonthsShort (m) {
        return this._monthsShort[m.month()];
    }

    function localeMonthsParse (monthName, format, strict) {
        var i, mom, regex;

        if (!this._monthsParse) {
            this._monthsParse = [];
            this._longMonthsParse = [];
            this._shortMonthsParse = [];
        }

        for (i = 0; i < 12; i++) {
            // make the regex if we don't have it already
            mom = create_utc__createUTC([2000, i]);
            if (strict && !this._longMonthsParse[i]) {
                this._longMonthsParse[i] = new RegExp("^" + this.months(mom, "").replace(".", "") + "$", "i");
                this._shortMonthsParse[i] = new RegExp("^" + this.monthsShort(mom, "").replace(".", "") + "$", "i");
            }
            if (!strict && !this._monthsParse[i]) {
                regex = "^" + this.months(mom, "") + "|^" + this.monthsShort(mom, "");
                this._monthsParse[i] = new RegExp(regex.replace(".", ""), "i");
            }
            // test the regex
            if (strict && format === "MMMM" && this._longMonthsParse[i].test(monthName)) {
                return i;
            } else if (strict && format === "MMM" && this._shortMonthsParse[i].test(monthName)) {
                return i;
            } else if (!strict && this._monthsParse[i].test(monthName)) {
                return i;
            }
        }
    }

    // MOMENTS

    function setMonth (mom, value) {
        var dayOfMonth;

        // TODO: Move this out of here!
        if (typeof value === "string") {
            value = mom.localeData().monthsParse(value);
            // TODO: Another silent failure?
            if (typeof value !== "number") {
                return mom;
            }
        }

        dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
        mom._d["set" + (mom._isUTC ? "UTC" : "") + "Month"](value, dayOfMonth);
        return mom;
    }

    function getSetMonth (value) {
        if (value != null) {
            setMonth(this, value);
            utils_hooks__hooks.updateOffset(this, true);
            return this;
        } else {
            return get_set__get(this, "Month");
        }
    }

    function getDaysInMonth () {
        return daysInMonth(this.year(), this.month());
    }

    function checkOverflow (m) {
        var overflow;
        var a = m._a;

        if (a && m._pf.overflow === -2) {
            overflow =
                a[MONTH]       < 0 || a[MONTH]       > 11  ? MONTH :
                a[DATE]        < 1 || a[DATE]        > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
                a[HOUR]        < 0 || a[HOUR]        > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
                a[MINUTE]      < 0 || a[MINUTE]      > 59  ? MINUTE :
                a[SECOND]      < 0 || a[SECOND]      > 59  ? SECOND :
                a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
                -1;

            if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
                overflow = DATE;
            }

            m._pf.overflow = overflow;
        }

        return m;
    }

    function warn(msg) {
        if (utils_hooks__hooks.suppressDeprecationWarnings === false && typeof console !== "undefined" && console.warn) {
            console.warn("Deprecation warning: " + msg);
        }
    }

    function deprecate(msg, fn) {
        var firstTime = true;
        return extend(function () {
            if (firstTime) {
                warn(msg);
                firstTime = false;
            }
            return fn.apply(this, arguments);
        }, fn);
    }

    var deprecations = {};

    function deprecateSimple(name, msg) {
        if (!deprecations[name]) {
            warn(msg);
            deprecations[name] = true;
        }
    }

    utils_hooks__hooks.suppressDeprecationWarnings = false;

    var from_string__isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;

    var isoDates = [
        ["YYYYYY-MM-DD", /[+-]\d{6}-\d{2}-\d{2}/],
        ["YYYY-MM-DD", /\d{4}-\d{2}-\d{2}/],
        ["GGGG-[W]WW-E", /\d{4}-W\d{2}-\d/],
        ["GGGG-[W]WW", /\d{4}-W\d{2}/],
        ["YYYY-DDD", /\d{4}-\d{3}/]
    ];

    // iso time formats and regexes
    var isoTimes = [
        ["HH:mm:ss.SSSS", /(T| )\d\d:\d\d:\d\d\.\d+/],
        ["HH:mm:ss", /(T| )\d\d:\d\d:\d\d/],
        ["HH:mm", /(T| )\d\d:\d\d/],
        ["HH", /(T| )\d\d/]
    ];

    var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;

    // date from iso format
    function configFromISO(config) {
        var i, l,
            string = config._i,
            match = from_string__isoRegex.exec(string);

        if (match) {
            config._pf.iso = true;
            for (i = 0, l = isoDates.length; i < l; i++) {
                if (isoDates[i][1].exec(string)) {
                    // match[5] should be 'T' or undefined
                    config._f = isoDates[i][0] + (match[6] || " ");
                    break;
                }
            }
            for (i = 0, l = isoTimes.length; i < l; i++) {
                if (isoTimes[i][1].exec(string)) {
                    config._f += isoTimes[i][0];
                    break;
                }
            }
            if (string.match(matchOffset)) {
                config._f += "Z";
            }
            configFromStringAndFormat(config);
        } else {
            config._isValid = false;
        }
    }

    // date from iso format or fallback
    function configFromString(config) {
        var matched = aspNetJsonRegex.exec(config._i);

        if (matched !== null) {
            config._d = new Date(+matched[1]);
            return;
        }

        configFromISO(config);
        if (config._isValid === false) {
            delete config._isValid;
            utils_hooks__hooks.createFromInputFallback(config);
        }
    }

    utils_hooks__hooks.createFromInputFallback = deprecate(
        "moment construction falls back to js Date. This is " +
        "discouraged and will be removed in upcoming major " +
        "release. Please refer to " +
        "https://github.com/moment/moment/issues/1407 for more info.",
        function (config) {
            config._d = new Date(config._i + (config._useUTC ? " UTC" : ""));
        }
    );

    function createDate (y, m, d, h, M, s, ms) {
        //can't just apply() to create a date:
        //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
        var date = new Date(y, m, d, h, M, s, ms);

        //the date constructor doesn't accept years < 1970
        if (y < 1970) {
            date.setFullYear(y);
        }
        return date;
    }

    function createUTCDate (y) {
        var date = new Date(Date.UTC.apply(null, arguments));
        if (y < 1970) {
            date.setUTCFullYear(y);
        }
        return date;
    }

    addFormatToken(0, ["YY", 2], 0, function () {
        return this.year() % 100;
    });

    addFormatToken(0, ["YYYY",   4],       0, "year");
    addFormatToken(0, ["YYYYY",  5],       0, "year");
    addFormatToken(0, ["YYYYYY", 6, true], 0, "year");

    // ALIASES

    addUnitAlias("year", "y");

    // PARSING

    addRegexToken("Y",      matchSigned);
    addRegexToken("YY",     match1to2, match2);
    addRegexToken("YYYY",   match1to4, match4);
    addRegexToken("YYYYY",  match1to6, match6);
    addRegexToken("YYYYYY", match1to6, match6);

    addParseToken(["YYYY", "YYYYY", "YYYYYY"], YEAR);
    addParseToken("YY", function (input, array) {
        array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input);
    });

    // HELPERS

    function daysInYear(year) {
        return isLeapYear(year) ? 366 : 365;
    }

    function isLeapYear(year) {
        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
    }

    // HOOKS

    utils_hooks__hooks.parseTwoDigitYear = function (input) {
        return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
    };

    // MOMENTS

    var getSetYear = makeGetSet("FullYear", false);

    function getIsLeapYear () {
        return isLeapYear(this.year());
    }

    addFormatToken("w", ["ww", 2], "wo", "week");
    addFormatToken("W", ["WW", 2], "Wo", "isoWeek");

    // ALIASES

    addUnitAlias("week", "w");
    addUnitAlias("isoWeek", "W");

    // PARSING

    addRegexToken("w",  match1to2);
    addRegexToken("ww", match1to2, match2);
    addRegexToken("W",  match1to2);
    addRegexToken("WW", match1to2, match2);

    addWeekParseToken(["w", "ww", "W", "WW"], function (input, week, config, token) {
        week[token.substr(0, 1)] = toInt(input);
    });

    // HELPERS

    // firstDayOfWeek       0 = sun, 6 = sat
    //                      the day of the week that starts the week
    //                      (usually sunday or monday)
    // firstDayOfWeekOfYear 0 = sun, 6 = sat
    //                      the first week is the week that contains the first
    //                      of this day of the week
    //                      (eg. ISO weeks use thursday (4))
    function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
        var end = firstDayOfWeekOfYear - firstDayOfWeek,
            daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
            adjustedMoment;


        if (daysToDayOfWeek > end) {
            daysToDayOfWeek -= 7;
        }

        if (daysToDayOfWeek < end - 7) {
            daysToDayOfWeek += 7;
        }

        adjustedMoment = local__createLocal(mom).add(daysToDayOfWeek, "d");
        return {
            week: Math.ceil(adjustedMoment.dayOfYear() / 7),
            year: adjustedMoment.year()
        };
    }

    // LOCALES

    function localeWeek (mom) {
        return weekOfYear(mom, this._week.dow, this._week.doy).week;
    }

    var defaultLocaleWeek = {
        dow: 0, // Sunday is the first day of the week.
        doy: 6  // The week that contains Jan 1st is the first week of the year.
    };

    function localeFirstDayOfWeek () {
        return this._week.dow;
    }

    function localeFirstDayOfYear () {
        return this._week.doy;
    }

    // MOMENTS

    function getSetWeek (input) {
        var week = this.localeData().week(this);
        return input == null ? week : this.add((input - week) * 7, "d");
    }

    function getSetISOWeek (input) {
        var week = weekOfYear(this, 1, 4).week;
        return input == null ? week : this.add((input - week) * 7, "d");
    }

    addFormatToken("DDD", ["DDDD", 3], "DDDo", "dayOfYear");

    // ALIASES

    addUnitAlias("dayOfYear", "DDD");

    // PARSING

    addRegexToken("DDD",  match1to3);
    addRegexToken("DDDD", match3);
    addParseToken(["DDD", "DDDD"], function (input, array, config) {
        config._dayOfYear = toInt(input);
    });

    // HELPERS

    //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
    function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {
        var d = createUTCDate(year, 0, 1).getUTCDay();
        var daysToAdd;
        var dayOfYear;

        d = d === 0 ? 7 : d;
        weekday = weekday != null ? weekday : firstDayOfWeek;
        daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0);
        dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1;

        return {
            year: dayOfYear > 0 ? year      : year - 1,
            dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear
        };
    }

    // MOMENTS

    function getSetDayOfYear (input) {
        var dayOfYear = Math.round((this.clone().startOf("day") - this.clone().startOf("year")) / 86400000) + 1;
        return input == null ? dayOfYear : this.add((input - dayOfYear), "d");
    }

    // Pick the first defined of two or three arguments.
    function defaults(a, b, c) {
        if (a != null) {
            return a;
        }
        if (b != null) {
            return b;
        }
        return c;
    }

    function currentDateArray(config) {
        var now = new Date();
        if (config._useUTC) {
            return [now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()];
        }
        return [now.getFullYear(), now.getMonth(), now.getDate()];
    }

    // convert an array to a date.
    // the array should mirror the parameters below
    // note: all values past the year are optional and will default to the lowest possible value.
    // [year, month, day , hour, minute, second, millisecond]
    function configFromArray (config) {
        var i, date, input = [], currentDate, yearToUse;

        if (config._d) {
            return;
        }

        currentDate = currentDateArray(config);

        //compute day of the year from weeks and weekdays
        if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
            dayOfYearFromWeekInfo(config);
        }

        //if the day of the year is set, figure out what it is
        if (config._dayOfYear) {
            yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);

            if (config._dayOfYear > daysInYear(yearToUse)) {
                config._pf._overflowDayOfYear = true;
            }

            date = createUTCDate(yearToUse, 0, config._dayOfYear);
            config._a[MONTH] = date.getUTCMonth();
            config._a[DATE] = date.getUTCDate();
        }

        // Default to current date.
        // * if no year, month, day of month are given, default to today
        // * if day of month is given, default month and year
        // * if month is given, default only year
        // * if year is given, don't default anything
        for (i = 0; i < 3 && config._a[i] == null; ++i) {
            config._a[i] = input[i] = currentDate[i];
        }

        // Zero out whatever was not defaulted, including time
        for (; i < 7; i++) {
            config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
        }

        // Check for 24:00:00.000
        if (config._a[HOUR] === 24 &&
                config._a[MINUTE] === 0 &&
                config._a[SECOND] === 0 &&
                config._a[MILLISECOND] === 0) {
            config._nextDay = true;
            config._a[HOUR] = 0;
        }

        config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
        // Apply timezone offset from input. The actual utcOffset can be changed
        // with parseZone.
        if (config._tzm != null) {
            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
        }

        if (config._nextDay) {
            config._a[HOUR] = 24;
        }
    }

    function dayOfYearFromWeekInfo(config) {
        var w, weekYear, week, weekday, dow, doy, temp;

        w = config._w;
        if (w.GG != null || w.W != null || w.E != null) {
            dow = 1;
            doy = 4;

            // TODO: We need to take the current isoWeekYear, but that depends on
            // how we interpret now (local, utc, fixed offset). So create
            // a now version of current config (take local/utc/offset flags, and
            // create now).
            weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year);
            week = defaults(w.W, 1);
            weekday = defaults(w.E, 1);
        } else {
            dow = config._locale._week.dow;
            doy = config._locale._week.doy;

            weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year);
            week = defaults(w.w, 1);

            if (w.d != null) {
                // weekday -- low day numbers are considered next week
                weekday = w.d;
                if (weekday < dow) {
                    ++week;
                }
            } else if (w.e != null) {
                // local weekday -- counting starts from begining of week
                weekday = w.e + dow;
            } else {
                // default to begining of week
                weekday = dow;
            }
        }
        temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow);

        config._a[YEAR] = temp.year;
        config._dayOfYear = temp.dayOfYear;
    }

    utils_hooks__hooks.ISO_8601 = function () {};

    // date from string and format string
    function configFromStringAndFormat(config) {
        // TODO: Move this to another part of the creation flow to prevent circular deps
        if (config._f === utils_hooks__hooks.ISO_8601) {
            configFromISO(config);
            return;
        }

        config._a = [];
        config._pf.empty = true;

        // This array is used to make a Date, either with `new Date` or `Date.UTC`
        var string = "" + config._i,
            i, parsedInput, tokens, token, skipped,
            stringLength = string.length,
            totalParsedInputLength = 0;

        tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];

        for (i = 0; i < tokens.length; i++) {
            token = tokens[i];
            parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
            if (parsedInput) {
                skipped = string.substr(0, string.indexOf(parsedInput));
                if (skipped.length > 0) {
                    config._pf.unusedInput.push(skipped);
                }
                string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
                totalParsedInputLength += parsedInput.length;
            }
            // don't parse if it's not a known token
            if (formatTokenFunctions[token]) {
                if (parsedInput) {
                    config._pf.empty = false;
                }
                else {
                    config._pf.unusedTokens.push(token);
                }
                addTimeToArrayFromToken(token, parsedInput, config);
            }
            else if (config._strict && !parsedInput) {
                config._pf.unusedTokens.push(token);
            }
        }

        // add remaining unparsed input length to the string
        config._pf.charsLeftOver = stringLength - totalParsedInputLength;
        if (string.length > 0) {
            config._pf.unusedInput.push(string);
        }

        // clear _12h flag if hour is <= 12
        if (config._pf.bigHour === true && config._a[HOUR] <= 12) {
            config._pf.bigHour = undefined;
        }
        // handle meridiem
        config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);

        configFromArray(config);
        checkOverflow(config);
    }


    function meridiemFixWrap (locale, hour, meridiem) {
        var isPm;

        if (meridiem == null) {
            // nothing to do
            return hour;
        }
        if (locale.meridiemHour != null) {
            return locale.meridiemHour(hour, meridiem);
        } else if (locale.isPM != null) {
            // Fallback
            isPm = locale.isPM(meridiem);
            if (isPm && hour < 12) {
                hour += 12;
            }
            if (!isPm && hour === 12) {
                hour = 0;
            }
            return hour;
        } else {
            // this is not supposed to happen
            return hour;
        }
    }

    function configFromStringAndArray(config) {
        var tempConfig,
            bestMoment,

            scoreToBeat,
            i,
            currentScore;

        if (config._f.length === 0) {
            config._pf.invalidFormat = true;
            config._d = new Date(NaN);
            return;
        }

        for (i = 0; i < config._f.length; i++) {
            currentScore = 0;
            tempConfig = copyConfig({}, config);
            if (config._useUTC != null) {
                tempConfig._useUTC = config._useUTC;
            }
            tempConfig._pf = defaultParsingFlags();
            tempConfig._f = config._f[i];
            configFromStringAndFormat(tempConfig);

            if (!valid__isValid(tempConfig)) {
                continue;
            }

            // if there is any input that was not parsed add a penalty for that format
            currentScore += tempConfig._pf.charsLeftOver;

            //or tokens
            currentScore += tempConfig._pf.unusedTokens.length * 10;

            tempConfig._pf.score = currentScore;

            if (scoreToBeat == null || currentScore < scoreToBeat) {
                scoreToBeat = currentScore;
                bestMoment = tempConfig;
            }
        }

        extend(config, bestMoment || tempConfig);
    }

    function configFromObject(config) {
        if (config._d) {
            return;
        }

        var i = normalizeObjectUnits(config._i);
        config._a = [i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond];

        configFromArray(config);
    }

    function createFromConfig (config) {
        var input = config._i,
            format = config._f,
            res;

        config._locale = config._locale || locale_locales__getLocale(config._l);

        if (input === null || (format === undefined && input === "")) {
            return valid__createInvalid({nullInput: true});
        }

        if (typeof input === "string") {
            config._i = input = config._locale.preparse(input);
        }

        if (isMoment(input)) {
            return new Moment(checkOverflow(input));
        } else if (isArray(format)) {
            configFromStringAndArray(config);
        } else if (format) {
            configFromStringAndFormat(config);
        } else {
            configFromInput(config);
        }

        res = new Moment(checkOverflow(config));
        if (res._nextDay) {
            // Adding is smart enough around DST
            res.add(1, "d");
            res._nextDay = undefined;
        }

        return res;
    }

    function configFromInput(config) {
        var input = config._i;
        if (input === undefined) {
            config._d = new Date();
        } else if (isDate(input)) {
            config._d = new Date(+input);
        } else if (typeof input === "string") {
            configFromString(config);
        } else if (isArray(input)) {
            config._a = map(input.slice(0), function (obj) {
                return parseInt(obj, 10);
            });
            configFromArray(config);
        } else if (typeof(input) === "object") {
            configFromObject(config);
        } else if (typeof(input) === "number") {
            // from milliseconds
            config._d = new Date(input);
        } else {
            utils_hooks__hooks.createFromInputFallback(config);
        }
    }

    function createLocalOrUTC (input, format, locale, strict, isUTC) {
        var c = {};

        if (typeof(locale) === "boolean") {
            strict = locale;
            locale = undefined;
        }
        // object construction must be done this way.
        // https://github.com/moment/moment/issues/1423
        c._isAMomentObject = true;
        c._useUTC = c._isUTC = isUTC;
        c._l = locale;
        c._i = input;
        c._f = format;
        c._strict = strict;
        c._pf = defaultParsingFlags();

        return createFromConfig(c);
    }

    function local__createLocal (input, format, locale, strict) {
        return createLocalOrUTC(input, format, locale, strict, false);
    }

    var prototypeMin = deprecate(
         "moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",
         function () {
             var other = local__createLocal.apply(null, arguments);
             return other < this ? this : other;
         }
     );

    var prototypeMax = deprecate(
        "moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",
        function () {
            var other = local__createLocal.apply(null, arguments);
            return other > this ? this : other;
        }
    );

    // Pick a moment m from moments so that m[fn](other) is true for all
    // other. This relies on the function fn to be transitive.
    //
    // moments should either be an array of moment objects or an array, whose
    // first element is an array of moment objects.
    function pickBy(fn, moments) {
        var res, i;
        if (moments.length === 1 && isArray(moments[0])) {
            moments = moments[0];
        }
        if (!moments.length) {
            return local__createLocal();
        }
        res = moments[0];
        for (i = 1; i < moments.length; ++i) {
            if (moments[i][fn](res)) {
                res = moments[i];
            }
        }
        return res;
    }

    // TODO: Use [].sort instead?
    function min () {
        var args = [].slice.call(arguments, 0);

        return pickBy("isBefore", args);
    }

    function max () {
        var args = [].slice.call(arguments, 0);

        return pickBy("isAfter", args);
    }

    function Duration (duration) {
        var normalizedInput = normalizeObjectUnits(duration),
            years = normalizedInput.year || 0,
            quarters = normalizedInput.quarter || 0,
            months = normalizedInput.month || 0,
            weeks = normalizedInput.week || 0,
            days = normalizedInput.day || 0,
            hours = normalizedInput.hour || 0,
            minutes = normalizedInput.minute || 0,
            seconds = normalizedInput.second || 0,
            milliseconds = normalizedInput.millisecond || 0;

        // representation for dateAddRemove
        // 1000 * 60 * 60
        this._milliseconds = +milliseconds +
            seconds * 1000 + // 1000
            minutes * 60000 + // 1000 * 60
            hours * 3600000;
        // Because of dateAddRemove treats 24 hours as different from a
        // day when working around DST, we need to store them separately
        this._days = +days +
            weeks * 7;
        // It is impossible translate months into days without knowing
        // which months you are are talking about, so we have to store
        // it separately.
        this._months = +months +
            quarters * 3 +
            years * 12;

        this._data = {};

        this._locale = locale_locales__getLocale();

        this._bubble();
    }

    function isDuration (obj) {
        return obj instanceof Duration;
    }

    function offset (token, separator) {
        addFormatToken(token, 0, 0, function () {
            var offset = this.utcOffset();
            var sign = "+";
            if (offset < 0) {
                offset = -offset;
                sign = "-";
            }
            return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
        });
    }

    offset("Z", ":");
    offset("ZZ", "");

    // PARSING

    addRegexToken("Z",  matchOffset);
    addRegexToken("ZZ", matchOffset);
    addParseToken(["Z", "ZZ"], function (input, array, config) {
        config._useUTC = true;
        config._tzm = offsetFromString(input);
    });

    // HELPERS

    // timezone chunker
    // '+10:00' > ['10',  '00']
    // '-1530'  > ['-15', '30']
    var chunkOffset = /([\+\-]|\d\d)/gi;

    function offsetFromString(string) {
        var matches = ((string || "").match(matchOffset) || []);
        var chunk   = matches[matches.length - 1] || [];
        var parts   = (chunk + "").match(chunkOffset) || ["-", 0, 0];
        var minutes = +(parts[1] * 60) + toInt(parts[2]);

        return parts[0] === "+" ? minutes : -minutes;
    }

    // Return a moment from input, that is local/utc/zone equivalent to model.
    function cloneWithOffset(input, model) {
        var res, diff;
        if (model._isUTC) {
            res = model.clone();
            diff = (isMoment(input) || isDate(input) ? +input : +local__createLocal(input)) - (+res);
            // Use low-level api, because this fn is low-level api.
            res._d.setTime(+res._d + diff);
            utils_hooks__hooks.updateOffset(res, false);
            return res;
        } else {
            return local__createLocal(input).local();
        }
        return model._isUTC ? local__createLocal(input).zone(model._offset || 0) : local__createLocal(input).local();
    }

    function getDateOffset (m) {
        // On Firefox.24 Date#getTimezoneOffset returns a floating point.
        // https://github.com/moment/moment/pull/1871
        return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
    }

    // HOOKS

    // This function will be called whenever a moment is mutated.
    // It is intended to keep the offset in sync with the timezone.
    utils_hooks__hooks.updateOffset = function () {};

    // MOMENTS

    // keepLocalTime = true means only change the timezone, without
    // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
    // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
    // +0200, so we adjust the time as needed, to be valid.
    //
    // Keeping the time actually adds/subtracts (one hour)
    // from the actual represented time. That is why we call updateOffset
    // a second time. In case it wants us to change the offset again
    // _changeInProgress == true case, then we have to adjust, because
    // there is no such time in the given timezone.
    function getSetOffset (input, keepLocalTime) {
        var offset = this._offset || 0,
            localAdjust;
        if (input != null) {
            if (typeof input === "string") {
                input = offsetFromString(input);
            }
            if (Math.abs(input) < 16) {
                input = input * 60;
            }
            if (!this._isUTC && keepLocalTime) {
                localAdjust = getDateOffset(this);
            }
            this._offset = input;
            this._isUTC = true;
            if (localAdjust != null) {
                this.add(localAdjust, "m");
            }
            if (offset !== input) {
                if (!keepLocalTime || this._changeInProgress) {
                    add_subtract__addSubtract(this, create__createDuration(input - offset, "m"), 1, false);
                } else if (!this._changeInProgress) {
                    this._changeInProgress = true;
                    utils_hooks__hooks.updateOffset(this, true);
                    this._changeInProgress = null;
                }
            }
            return this;
        } else {
            return this._isUTC ? offset : getDateOffset(this);
        }
    }

    function getSetZone (input, keepLocalTime) {
        if (input != null) {
            if (typeof input !== "string") {
                input = -input;
            }

            this.utcOffset(input, keepLocalTime);

            return this;
        } else {
            return -this.utcOffset();
        }
    }

    function setOffsetToUTC (keepLocalTime) {
        return this.utcOffset(0, keepLocalTime);
    }

    function setOffsetToLocal (keepLocalTime) {
        if (this._isUTC) {
            this.utcOffset(0, keepLocalTime);
            this._isUTC = false;

            if (keepLocalTime) {
                this.subtract(getDateOffset(this), "m");
            }
        }
        return this;
    }

    function setOffsetToParsedOffset () {
        if (this._tzm) {
            this.utcOffset(this._tzm);
        } else if (typeof this._i === "string") {
            this.utcOffset(offsetFromString(this._i));
        }
        return this;
    }

    function hasAlignedHourOffset (input) {
        if (!input) {
            input = 0;
        }
        else {
            input = local__createLocal(input).utcOffset();
        }

        return (this.utcOffset() - input) % 60 === 0;
    }

    function isDaylightSavingTime () {
        return (
            this.utcOffset() > this.clone().month(0).utcOffset() ||
            this.utcOffset() > this.clone().month(5).utcOffset()
        );
    }

    function isDaylightSavingTimeShifted () {
        if (this._a) {
            var other = this._isUTC ? create_utc__createUTC(this._a) : local__createLocal(this._a);
            return this.isValid() && compareArrays(this._a, other.toArray()) > 0;
        }

        return false;
    }

    function isLocal () {
        return !this._isUTC;
    }

    function isUtcOffset () {
        return this._isUTC;
    }

    function isUtc () {
        return this._isUTC && this._offset === 0;
    }

    var aspNetRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/;

    // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
    // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
    var create__isoRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;

    function create__createDuration (input, key) {
        var duration = input,
            // matching against regexp is expensive, do it on demand
            match = null,
            sign,
            ret,
            diffRes;

        if (isDuration(input)) {
            duration = {
                ms: input._milliseconds,
                d: input._days,
                M: input._months
            };
        } else if (typeof input === "number") {
            duration = {};
            if (key) {
                duration[key] = input;
            } else {
                duration.milliseconds = input;
            }
        } else if (!!(match = aspNetRegex.exec(input))) {
            sign = (match[1] === "-") ? -1 : 1;
            duration = {
                y: 0,
                d: toInt(match[DATE])        * sign,
                h: toInt(match[HOUR])        * sign,
                m: toInt(match[MINUTE])      * sign,
                s: toInt(match[SECOND])      * sign,
                ms: toInt(match[MILLISECOND]) * sign
            };
        } else if (!!(match = create__isoRegex.exec(input))) {
            sign = (match[1] === "-") ? -1 : 1;
            duration = {
                y: parseIso(match[2], sign),
                M: parseIso(match[3], sign),
                d: parseIso(match[4], sign),
                h: parseIso(match[5], sign),
                m: parseIso(match[6], sign),
                s: parseIso(match[7], sign),
                w: parseIso(match[8], sign)
            };
        } else if (duration == null) {
            // checks for null or undefined
            duration = {};
        } else if (typeof duration === "object" && ("from" in duration || "to" in duration)) {
            diffRes = momentsDifference(local__createLocal(duration.from), local__createLocal(duration.to));

            duration = {};
            duration.ms = diffRes.milliseconds;
            duration.M = diffRes.months;
        }

        ret = new Duration(duration);

        if (isDuration(input) && hasOwnProp(input, "_locale")) {
            ret._locale = input._locale;
        }

        return ret;
    }

    create__createDuration.fn = Duration.prototype;

    function parseIso (inp, sign) {
        // We'd normally use ~~inp for this, but unfortunately it also
        // converts floats to ints.
        // inp may be undefined, so careful calling replace on it.
        var res = inp && parseFloat(inp.replace(",", "."));
        // apply sign while we're at it
        return (isNaN(res) ? 0 : res) * sign;
    }

    function positiveMomentsDifference(base, other) {
        var res = {milliseconds: 0, months: 0};

        res.months = other.month() - base.month() +
            (other.year() - base.year()) * 12;
        if (base.clone().add(res.months, "M").isAfter(other)) {
            --res.months;
        }

        res.milliseconds = +other - +(base.clone().add(res.months, "M"));

        return res;
    }

    function momentsDifference(base, other) {
        var res;
        other = cloneWithOffset(other, base);
        if (base.isBefore(other)) {
            res = positiveMomentsDifference(base, other);
        } else {
            res = positiveMomentsDifference(other, base);
            res.milliseconds = -res.milliseconds;
            res.months = -res.months;
        }

        return res;
    }

    function createAdder(direction, name) {
        return function (val, period) {
            var dur, tmp;
            //invert the arguments, but complain about it
            if (period !== null && !isNaN(+period)) {
                deprecateSimple(name, "moment()." + name  + "(period, number) is deprecated. Please use moment()." + name + "(number, period).");
                tmp = val;val = period;period = tmp;
            }

            val = typeof val === "string" ? +val : val;
            dur = create__createDuration(val, period);
            add_subtract__addSubtract(this, dur, direction);
            return this;
        };
    }

    function add_subtract__addSubtract (mom, duration, isAdding, updateOffset) {
        var milliseconds = duration._milliseconds,
            days = duration._days,
            months = duration._months;
        updateOffset = updateOffset == null ? true : updateOffset;

        if (milliseconds) {
            mom._d.setTime(+mom._d + milliseconds * isAdding);
        }
        if (days) {
            get_set__set(mom, "Date", get_set__get(mom, "Date") + days * isAdding);
        }
        if (months) {
            setMonth(mom, get_set__get(mom, "Month") + months * isAdding);
        }
        if (updateOffset) {
            utils_hooks__hooks.updateOffset(mom, days || months);
        }
    }

    var add_subtract__add      = createAdder(1, "add");
    var add_subtract__subtract = createAdder(-1, "subtract");

    function moment_calendar__calendar (time) {
        // We want to compare the start of today, vs this.
        // Getting start-of-today depends on whether we're local/utc/offset or not.
        var now = time || local__createLocal(),
            sod = cloneWithOffset(now, this).startOf("day"),
            diff = this.diff(sod, "days", true),
            format = diff < -6 ? "sameElse" :
                diff < -1 ? "lastWeek" :
                diff < 0 ? "lastDay" :
                diff < 1 ? "sameDay" :
                diff < 2 ? "nextDay" :
                diff < 7 ? "nextWeek" : "sameElse";
        return this.format(this.localeData().calendar(format, this, local__createLocal(now)));
    }

    function clone () {
        return new Moment(this);
    }

    function isAfter (input, units) {
        var inputMs;
        units = normalizeUnits(typeof units !== "undefined" ? units : "millisecond");
        if (units === "millisecond") {
            input = isMoment(input) ? input : local__createLocal(input);
            return +this > +input;
        } else {
            inputMs = isMoment(input) ? +input : +local__createLocal(input);
            return inputMs < +this.clone().startOf(units);
        }
    }

    function isBefore (input, units) {
        var inputMs;
        units = normalizeUnits(typeof units !== "undefined" ? units : "millisecond");
        if (units === "millisecond") {
            input = isMoment(input) ? input : local__createLocal(input);
            return +this < +input;
        } else {
            inputMs = isMoment(input) ? +input : +local__createLocal(input);
            return +this.clone().endOf(units) < inputMs;
        }
    }

    function isBetween (from, to, units) {
        return this.isAfter(from, units) && this.isBefore(to, units);
    }

    function isSame (input, units) {
        var inputMs;
        units = normalizeUnits(units || "millisecond");
        if (units === "millisecond") {
            input = isMoment(input) ? input : local__createLocal(input);
            return +this === +input;
        } else {
            inputMs = +local__createLocal(input);
            return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units));
        }
    }

    function absFloor (number) {
        if (number < 0) {
            return Math.ceil(number);
        } else {
            return Math.floor(number);
        }
    }

    function diff (input, units, asFloat) {
        var that = cloneWithOffset(input, this),
            zoneDelta = (that.utcOffset() - this.utcOffset()) * 60000,
            delta, output;

        units = normalizeUnits(units);

        if (units === "year" || units === "month" || units === "quarter") {
            output = monthDiff(this, that);
            if (units === "quarter") {
                output = output / 3;
            } else if (units === "year") {
                output = output / 12;
            }
        } else {
            delta = this - that;
            output = units === "second" ? delta / 1000 : // 1000
                units === "minute" ? delta / 60000 : // 1000 * 60
                units === "hour" ? delta / 3600000 : // 1000 * 60 * 60
                units === "day" ? (delta - zoneDelta) / 86400000 : // 1000 * 60 * 60 * 24, negate dst
                units === "week" ? (delta - zoneDelta) / 604800000 : // 1000 * 60 * 60 * 24 * 7, negate dst
                delta;
        }
        return asFloat ? output : absFloor(output);
    }

    function monthDiff (a, b) {
        // difference in months
        var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
            // b is in (anchor - 1 month, anchor + 1 month)
            anchor = a.clone().add(wholeMonthDiff, "months"),
            anchor2, adjust;

        if (b - anchor < 0) {
            anchor2 = a.clone().add(wholeMonthDiff - 1, "months");
            // linear across the month
            adjust = (b - anchor) / (anchor - anchor2);
        } else {
            anchor2 = a.clone().add(wholeMonthDiff + 1, "months");
            // linear across the month
            adjust = (b - anchor) / (anchor2 - anchor);
        }

        return -(wholeMonthDiff + adjust);
    }

    utils_hooks__hooks.defaultFormat = "YYYY-MM-DDTHH:mm:ssZ";

    function toString () {
        return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
    }

    function moment_format__toISOString () {
        var m = this.clone().utc();
        if (0 < m.year() && m.year() <= 9999) {
            if ("function" === typeof Date.prototype.toISOString) {
                // native implementation is ~50x faster, use it when we can
                return this.toDate().toISOString();
            } else {
                return formatMoment(m, "YYYY-MM-DD[T]HH:mm:ss.SSS[Z]");
            }
        } else {
            return formatMoment(m, "YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]");
        }
    }

    function format (inputString) {
        var output = formatMoment(this, inputString || utils_hooks__hooks.defaultFormat);
        return this.localeData().postformat(output);
    }

    function from (time, withoutSuffix) {
        return create__createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
    }

    function fromNow (withoutSuffix) {
        return this.from(local__createLocal(), withoutSuffix);
    }

    function locale (key) {
        var newLocaleData;

        if (key === undefined) {
            return this._locale._abbr;
        } else {
            newLocaleData = locale_locales__getLocale(key);
            if (newLocaleData != null) {
                this._locale = newLocaleData;
            }
            return this;
        }
    }

    var lang = deprecate(
        "moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",
        function (key) {
            if (key === undefined) {
                return this.localeData();
            } else {
                return this.locale(key);
            }
        }
    );

    function localeData () {
        return this._locale;
    }

    function startOf (units) {
        units = normalizeUnits(units);
        // the following switch intentionally omits break keywords
        // to utilize falling through the cases.
        switch (units) {
        case "year":
            this.month(0);
            /* falls through */
        case "quarter":
        case "month":
            this.date(1);
            /* falls through */
        case "week":
        case "isoWeek":
        case "day":
            this.hours(0);
            /* falls through */
        case "hour":
            this.minutes(0);
            /* falls through */
        case "minute":
            this.seconds(0);
            /* falls through */
        case "second":
            this.milliseconds(0);
        }

        // weeks are a special case
        if (units === "week") {
            this.weekday(0);
        }
        if (units === "isoWeek") {
            this.isoWeekday(1);
        }

        // quarters are also special
        if (units === "quarter") {
            this.month(Math.floor(this.month() / 3) * 3);
        }

        return this;
    }

    function endOf (units) {
        units = normalizeUnits(units);
        if (units === undefined || units === "millisecond") {
            return this;
        }
        return this.startOf(units).add(1, (units === "isoWeek" ? "week" : units)).subtract(1, "ms");
    }

    function to_type__valueOf () {
        return +this._d - ((this._offset || 0) * 60000);
    }

    function unix () {
        return Math.floor(+this / 1000);
    }

    function toDate () {
        return this._offset ? new Date(+this) : this._d;
    }

    function toArray () {
        var m = this;
        return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
    }

    function moment_valid__isValid () {
        return valid__isValid(this);
    }

    function parsingFlags () {
        return extend({}, this._pf);
    }

    function invalidAt () {
        return this._pf.overflow;
    }

    addFormatToken(0, ["gg", 2], 0, function () {
        return this.weekYear() % 100;
    });

    addFormatToken(0, ["GG", 2], 0, function () {
        return this.isoWeekYear() % 100;
    });

    function addWeekYearFormatToken (token, getter) {
        addFormatToken(0, [token, token.length], 0, getter);
    }

    addWeekYearFormatToken("gggg",     "weekYear");
    addWeekYearFormatToken("ggggg",    "weekYear");
    addWeekYearFormatToken("GGGG",  "isoWeekYear");
    addWeekYearFormatToken("GGGGG", "isoWeekYear");

    // ALIASES

    addUnitAlias("weekYear", "gg");
    addUnitAlias("isoWeekYear", "GG");

    // PARSING

    addRegexToken("G",      matchSigned);
    addRegexToken("g",      matchSigned);
    addRegexToken("GG",     match1to2, match2);
    addRegexToken("gg",     match1to2, match2);
    addRegexToken("GGGG",   match1to4, match4);
    addRegexToken("gggg",   match1to4, match4);
    addRegexToken("GGGGG",  match1to6, match6);
    addRegexToken("ggggg",  match1to6, match6);

    addWeekParseToken(["gggg", "ggggg", "GGGG", "GGGGG"], function (input, week, config, token) {
        week[token.substr(0, 2)] = toInt(input);
    });

    addWeekParseToken(["gg", "GG"], function (input, week, config, token) {
        week[token] = utils_hooks__hooks.parseTwoDigitYear(input);
    });

    // HELPERS

    function weeksInYear(year, dow, doy) {
        return weekOfYear(local__createLocal([year, 11, 31 + dow - doy]), dow, doy).week;
    }

    // MOMENTS

    function getSetWeekYear (input) {
        var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year;
        return input == null ? year : this.add((input - year), "y");
    }

    function getSetISOWeekYear (input) {
        var year = weekOfYear(this, 1, 4).year;
        return input == null ? year : this.add((input - year), "y");
    }

    function getISOWeeksInYear () {
        return weeksInYear(this.year(), 1, 4);
    }

    function getWeeksInYear () {
        var weekInfo = this.localeData()._week;
        return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
    }

    addFormatToken("Q", 0, 0, "quarter");

    // ALIASES

    addUnitAlias("quarter", "Q");

    // PARSING

    addRegexToken("Q", match1);
    addParseToken("Q", function (input, array) {
        array[MONTH] = (toInt(input) - 1) * 3;
    });

    // MOMENTS

    function getSetQuarter (input) {
        return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
    }

    addFormatToken("D", ["DD", 2], "Do", "date");

    // ALIASES

    addUnitAlias("date", "D");

    // PARSING

    addRegexToken("D",  match1to2);
    addRegexToken("DD", match1to2, match2);
    addRegexToken("Do", function (isStrict, locale) {
        return isStrict ? locale._ordinalParse : locale._ordinalParseLenient;
    });

    addParseToken(["D", "DD"], DATE);
    addParseToken("Do", function (input, array) {
        array[DATE] = toInt(input.match(match1to2)[0], 10);
    });

    // MOMENTS

    var getSetDayOfMonth = makeGetSet("Date", true);

    addFormatToken("d", 0, "do", "day");

    addFormatToken("dd", 0, 0, function (format) {
        return this.localeData().weekdaysMin(this, format);
    });

    addFormatToken("ddd", 0, 0, function (format) {
        return this.localeData().weekdaysShort(this, format);
    });

    addFormatToken("dddd", 0, 0, function (format) {
        return this.localeData().weekdays(this, format);
    });

    addFormatToken("e", 0, 0, "weekday");
    addFormatToken("E", 0, 0, "isoWeekday");

    // ALIASES

    addUnitAlias("day", "d");
    addUnitAlias("weekday", "e");
    addUnitAlias("isoWeekday", "E");

    // PARSING

    addRegexToken("d",    match1to2);
    addRegexToken("e",    match1to2);
    addRegexToken("E",    match1to2);
    addRegexToken("dd",   matchWord);
    addRegexToken("ddd",  matchWord);
    addRegexToken("dddd", matchWord);

    addWeekParseToken(["dd", "ddd", "dddd"], function (input, week, config) {
        var weekday = config._locale.weekdaysParse(input);
        // if we didn't get a weekday name, mark the date as invalid
        if (weekday != null) {
            week.d = weekday;
        } else {
            config._pf.invalidWeekday = input;
        }
    });

    addWeekParseToken(["d", "e", "E"], function (input, week, config, token) {
        week[token] = toInt(input);
    });

    // HELPERS

    function parseWeekday(input, locale) {
        if (typeof input === "string") {
            if (!isNaN(input)) {
                input = parseInt(input, 10);
            }
            else {
                input = locale.weekdaysParse(input);
                if (typeof input !== "number") {
                    return null;
                }
            }
        }
        return input;
    }

    // LOCALES

    var defaultLocaleWeekdays = "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_");
    function localeWeekdays (m) {
        return this._weekdays[m.day()];
    }

    var defaultLocaleWeekdaysShort = "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_");
    function localeWeekdaysShort (m) {
        return this._weekdaysShort[m.day()];
    }

    var defaultLocaleWeekdaysMin = "Su_Mo_Tu_We_Th_Fr_Sa".split("_");
    function localeWeekdaysMin (m) {
        return this._weekdaysMin[m.day()];
    }

    function localeWeekdaysParse (weekdayName) {
        var i, mom, regex;

        if (!this._weekdaysParse) {
            this._weekdaysParse = [];
        }

        for (i = 0; i < 7; i++) {
            // make the regex if we don't have it already
            if (!this._weekdaysParse[i]) {
                mom = local__createLocal([2000, 1]).day(i);
                regex = "^" + this.weekdays(mom, "") + "|^" + this.weekdaysShort(mom, "") + "|^" + this.weekdaysMin(mom, "");
                this._weekdaysParse[i] = new RegExp(regex.replace(".", ""), "i");
            }
            // test the regex
            if (this._weekdaysParse[i].test(weekdayName)) {
                return i;
            }
        }
    }

    // MOMENTS

    function getSetDayOfWeek (input) {
        var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
        if (input != null) {
            input = parseWeekday(input, this.localeData());
            return this.add(input - day, "d");
        } else {
            return day;
        }
    }

    function getSetLocaleDayOfWeek (input) {
        var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
        return input == null ? weekday : this.add(input - weekday, "d");
    }

    function getSetISODayOfWeek (input) {
        // behaves the same as moment#day except
        // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
        // as a setter, sunday should belong to the previous week.
        return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
    }

    addFormatToken("H", ["HH", 2], 0, "hour");
    addFormatToken("h", ["hh", 2], 0, function () {
        return this.hours() % 12 || 12;
    });

    function meridiem (token, lowercase) {
        addFormatToken(token, 0, 0, function () {
            return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
        });
    }

    meridiem("a", true);
    meridiem("A", false);

    // ALIASES

    addUnitAlias("hour", "h");

    // PARSING

    function matchMeridiem (isStrict, locale) {
        return locale._meridiemParse;
    }

    addRegexToken("a",  matchMeridiem);
    addRegexToken("A",  matchMeridiem);
    addRegexToken("H",  match1to2);
    addRegexToken("h",  match1to2);
    addRegexToken("HH", match1to2, match2);
    addRegexToken("hh", match1to2, match2);

    addParseToken(["H", "HH"], HOUR);
    addParseToken(["a", "A"], function (input, array, config) {
        config._isPm = config._locale.isPM(input);
        config._meridiem = input;
    });
    addParseToken(["h", "hh"], function (input, array, config) {
        array[HOUR] = toInt(input);
        config._pf.bigHour = true;
    });

    // LOCALES

    function localeIsPM (input) {
        // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
        // Using charAt should be more compatible.
        return ((input + "").toLowerCase().charAt(0) === "p");
    }

    var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
    function localeMeridiem (hours, minutes, isLower) {
        if (hours > 11) {
            return isLower ? "pm" : "PM";
        } else {
            return isLower ? "am" : "AM";
        }
    }


    // MOMENTS

    // Setting the hour should keep the time, because the user explicitly
    // specified which hour he wants. So trying to maintain the same hour (in
    // a new timezone) makes sense. Adding/subtracting hours does not follow
    // this rule.
    var getSetHour = makeGetSet("Hours", true);

    addFormatToken("m", ["mm", 2], 0, "minute");

    // ALIASES

    addUnitAlias("minute", "m");

    // PARSING

    addRegexToken("m",  match1to2);
    addRegexToken("mm", match1to2, match2);
    addParseToken(["m", "mm"], MINUTE);

    // MOMENTS

    var getSetMinute = makeGetSet("Minutes", false);

    addFormatToken("s", ["ss", 2], 0, "second");

    // ALIASES

    addUnitAlias("second", "s");

    // PARSING

    addRegexToken("s",  match1to2);
    addRegexToken("ss", match1to2, match2);
    addParseToken(["s", "ss"], SECOND);

    // MOMENTS

    var getSetSecond = makeGetSet("Seconds", false);

    addFormatToken("S", 0, 0, function () {
        return ~~(this.millisecond() / 100);
    });

    addFormatToken(0, ["SS", 2], 0, function () {
        return ~~(this.millisecond() / 10);
    });

    function millisecond__milliseconds (token) {
        addFormatToken(0, [token, 3], 0, "millisecond");
    }

    millisecond__milliseconds("SSS");
    millisecond__milliseconds("SSSS");

    // ALIASES

    addUnitAlias("millisecond", "ms");

    // PARSING

    addRegexToken("S",    match1to3, match1);
    addRegexToken("SS",   match1to3, match2);
    addRegexToken("SSS",  match1to3, match3);
    addRegexToken("SSSS", matchUnsigned);
    addParseToken(["S", "SS", "SSS", "SSSS"], function (input, array) {
        array[MILLISECOND] = toInt(("0." + input) * 1000);
    });

    // MOMENTS

    var getSetMillisecond = makeGetSet("Milliseconds", false);

    addFormatToken("z",  0, 0, "zoneAbbr");
    addFormatToken("zz", 0, 0, "zoneName");

    // MOMENTS

    function getZoneAbbr () {
        return this._isUTC ? "UTC" : "";
    }

    function getZoneName () {
        return this._isUTC ? "Coordinated Universal Time" : "";
    }

    var momentPrototype__proto = Moment.prototype;

    momentPrototype__proto.add          = add_subtract__add;
    momentPrototype__proto.calendar     = moment_calendar__calendar;
    momentPrototype__proto.clone        = clone;
    momentPrototype__proto.diff         = diff;
    momentPrototype__proto.endOf        = endOf;
    momentPrototype__proto.format       = format;
    momentPrototype__proto.from         = from;
    momentPrototype__proto.fromNow      = fromNow;
    momentPrototype__proto.get          = getSet;
    momentPrototype__proto.invalidAt    = invalidAt;
    momentPrototype__proto.isAfter      = isAfter;
    momentPrototype__proto.isBefore     = isBefore;
    momentPrototype__proto.isBetween    = isBetween;
    momentPrototype__proto.isSame       = isSame;
    momentPrototype__proto.isValid      = moment_valid__isValid;
    momentPrototype__proto.lang         = lang;
    momentPrototype__proto.locale       = locale;
    momentPrototype__proto.localeData   = localeData;
    momentPrototype__proto.max          = prototypeMax;
    momentPrototype__proto.min          = prototypeMin;
    momentPrototype__proto.parsingFlags = parsingFlags;
    momentPrototype__proto.set          = getSet;
    momentPrototype__proto.startOf      = startOf;
    momentPrototype__proto.subtract     = add_subtract__subtract;
    momentPrototype__proto.toArray      = toArray;
    momentPrototype__proto.toDate       = toDate;
    momentPrototype__proto.toISOString  = moment_format__toISOString;
    momentPrototype__proto.toJSON       = moment_format__toISOString;
    momentPrototype__proto.toString     = toString;
    momentPrototype__proto.unix         = unix;
    momentPrototype__proto.valueOf      = to_type__valueOf;

    // Year
    momentPrototype__proto.year       = getSetYear;
    momentPrototype__proto.isLeapYear = getIsLeapYear;

    // Week Year
    momentPrototype__proto.weekYear    = getSetWeekYear;
    momentPrototype__proto.isoWeekYear = getSetISOWeekYear;

    // Quarter
    momentPrototype__proto.quarter = momentPrototype__proto.quarters = getSetQuarter;

    // Month
    momentPrototype__proto.month       = getSetMonth;
    momentPrototype__proto.daysInMonth = getDaysInMonth;

    // Week
    momentPrototype__proto.week           = momentPrototype__proto.weeks        = getSetWeek;
    momentPrototype__proto.isoWeek        = momentPrototype__proto.isoWeeks     = getSetISOWeek;
    momentPrototype__proto.weeksInYear    = getWeeksInYear;
    momentPrototype__proto.isoWeeksInYear = getISOWeeksInYear;

    // Day
    momentPrototype__proto.date       = getSetDayOfMonth;
    momentPrototype__proto.day        = momentPrototype__proto.days             = getSetDayOfWeek;
    momentPrototype__proto.weekday    = getSetLocaleDayOfWeek;
    momentPrototype__proto.isoWeekday = getSetISODayOfWeek;
    momentPrototype__proto.dayOfYear  = getSetDayOfYear;

    // Hour
    momentPrototype__proto.hour = momentPrototype__proto.hours = getSetHour;

    // Minute
    momentPrototype__proto.minute = momentPrototype__proto.minutes = getSetMinute;

    // Second
    momentPrototype__proto.second = momentPrototype__proto.seconds = getSetSecond;

    // Millisecond
    momentPrototype__proto.millisecond = momentPrototype__proto.milliseconds = getSetMillisecond;

    // Offset
    momentPrototype__proto.utcOffset            = getSetOffset;
    momentPrototype__proto.utc                  = setOffsetToUTC;
    momentPrototype__proto.local                = setOffsetToLocal;
    momentPrototype__proto.parseZone            = setOffsetToParsedOffset;
    momentPrototype__proto.hasAlignedHourOffset = hasAlignedHourOffset;
    momentPrototype__proto.isDST                = isDaylightSavingTime;
    momentPrototype__proto.isDSTShifted         = isDaylightSavingTimeShifted;
    momentPrototype__proto.isLocal              = isLocal;
    momentPrototype__proto.isUtcOffset          = isUtcOffset;
    momentPrototype__proto.isUtc                = isUtc;
    momentPrototype__proto.isUTC                = isUtc;

    // Timezone
    momentPrototype__proto.zoneAbbr = getZoneAbbr;
    momentPrototype__proto.zoneName = getZoneName;

    // Deprecations
    momentPrototype__proto.dates  = deprecate("dates accessor is deprecated. Use date instead.", getSetDayOfMonth);
    momentPrototype__proto.months = deprecate("months accessor is deprecated. Use month instead", getSetMonth);
    momentPrototype__proto.years  = deprecate("years accessor is deprecated. Use year instead", getSetYear);
    momentPrototype__proto.zone   = deprecate("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779", getSetZone);

    var momentPrototype = momentPrototype__proto;

    function moment__createUnix (input) {
        return local__createLocal(input * 1000);
    }

    function moment__createInZone () {
        return local__createLocal.apply(null, arguments).parseZone();
    }

    var defaultCalendar = {
        sameDay: "[Today at] LT",
        nextDay: "[Tomorrow at] LT",
        nextWeek: "dddd [at] LT",
        lastDay: "[Yesterday at] LT",
        lastWeek: "[Last] dddd [at] LT",
        sameElse: "L"
    };

    function locale_calendar__calendar (key, mom, now) {
        var output = this._calendar[key];
        return typeof output === "function" ? output.call(mom, now) : output;
    }

    var defaultLongDateFormat = {
        LTS: "h:mm:ss A",
        LT: "h:mm A",
        L: "MM/DD/YYYY",
        LL: "MMMM D, YYYY",
        LLL: "MMMM D, YYYY LT",
        LLLL: "dddd, MMMM D, YYYY LT"
    };

    function longDateFormat (key) {
        var output = this._longDateFormat[key];
        if (!output && this._longDateFormat[key.toUpperCase()]) {
            output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
                return val.slice(1);
            });
            this._longDateFormat[key] = output;
        }
        return output;
    }

    var defaultInvalidDate = "Invalid date";

    function invalidDate () {
        return this._invalidDate;
    }

    var defaultOrdinal = "%d";
    var defaultOrdinalParse = /\d{1,2}/;

    function ordinal (number) {
        return this._ordinal.replace("%d", number);
    }

    function preParsePostFormat (string) {
        return string;
    }

    var defaultRelativeTime = {
        future: "in %s",
        past: "%s ago",
        s: "a few seconds",
        m: "a minute",
        mm: "%d minutes",
        h: "an hour",
        hh: "%d hours",
        d: "a day",
        dd: "%d days",
        M: "a month",
        MM: "%d months",
        y: "a year",
        yy: "%d years"
    };

    function relative__relativeTime (number, withoutSuffix, string, isFuture) {
        var output = this._relativeTime[string];
        return (typeof output === "function") ?
            output(number, withoutSuffix, string, isFuture) :
            output.replace(/%d/i, number);
    }

    function pastFuture (diff, output) {
        var format = this._relativeTime[diff > 0 ? "future" : "past"];
        return typeof format === "function" ? format(output) : format.replace(/%s/i, output);
    }

    function locale_set__set (config) {
        var prop, i;
        for (i in config) {
            prop = config[i];
            if (typeof prop === "function") {
                this[i] = prop;
            } else {
                this["_" + i] = prop;
            }
        }
        // Lenient ordinal parsing accepts just a number in addition to
        // number + (possibly) stuff coming from _ordinalParseLenient.
        this._ordinalParseLenient = new RegExp(this._ordinalParse.source + "|" + /\d{1,2}/.source);
    }

    var prototype__proto = Locale.prototype;

    prototype__proto._calendar       = defaultCalendar;
    prototype__proto.calendar        = locale_calendar__calendar;
    prototype__proto._longDateFormat = defaultLongDateFormat;
    prototype__proto.longDateFormat  = longDateFormat;
    prototype__proto._invalidDate    = defaultInvalidDate;
    prototype__proto.invalidDate     = invalidDate;
    prototype__proto._ordinal        = defaultOrdinal;
    prototype__proto.ordinal         = ordinal;
    prototype__proto._ordinalParse   = defaultOrdinalParse;
    prototype__proto.preparse        = preParsePostFormat;
    prototype__proto.postformat      = preParsePostFormat;
    prototype__proto._relativeTime   = defaultRelativeTime;
    prototype__proto.relativeTime    = relative__relativeTime;
    prototype__proto.pastFuture      = pastFuture;
    prototype__proto.set             = locale_set__set;

    // Month
    prototype__proto.months       =        localeMonths;
    prototype__proto._months      = defaultLocaleMonths;
    prototype__proto.monthsShort  =        localeMonthsShort;
    prototype__proto._monthsShort = defaultLocaleMonthsShort;
    prototype__proto.monthsParse  =        localeMonthsParse;

    // Week
    prototype__proto.week = localeWeek;
    prototype__proto._week = defaultLocaleWeek;
    prototype__proto.firstDayOfYear = localeFirstDayOfYear;
    prototype__proto.firstDayOfWeek = localeFirstDayOfWeek;

    // Day of Week
    prototype__proto.weekdays       =        localeWeekdays;
    prototype__proto._weekdays      = defaultLocaleWeekdays;
    prototype__proto.weekdaysMin    =        localeWeekdaysMin;
    prototype__proto._weekdaysMin   = defaultLocaleWeekdaysMin;
    prototype__proto.weekdaysShort  =        localeWeekdaysShort;
    prototype__proto._weekdaysShort = defaultLocaleWeekdaysShort;
    prototype__proto.weekdaysParse  =        localeWeekdaysParse;

    // Hours
    prototype__proto.isPM = localeIsPM;
    prototype__proto._meridiemParse = defaultLocaleMeridiemParse;
    prototype__proto.meridiem = localeMeridiem;

    function lists__get (format, index, field, setter) {
        var locale = locale_locales__getLocale();
        var utc = create_utc__createUTC().set(setter, index);
        return locale[field](utc, format);
    }

    function list (format, index, field, count, setter) {
        if (typeof format === "number") {
            index = format;
            format = undefined;
        }

        format = format || "";

        if (index != null) {
            return lists__get(format, index, field, setter);
        }

        var i;
        var out = [];
        for (i = 0; i < count; i++) {
            out[i] = lists__get(format, i, field, setter);
        }
        return out;
    }

    function lists__listMonths (format, index) {
        return list(format, index, "months", 12, "month");
    }

    function lists__listMonthsShort (format, index) {
        return list(format, index, "monthsShort", 12, "month");
    }

    function lists__listWeekdays (format, index) {
        return list(format, index, "weekdays", 7, "day");
    }

    function lists__listWeekdaysShort (format, index) {
        return list(format, index, "weekdaysShort", 7, "day");
    }

    function lists__listWeekdaysMin (format, index) {
        return list(format, index, "weekdaysMin", 7, "day");
    }

    locale_locales__getSetGlobalLocale("en", {
        ordinalParse: /\d{1,2}(th|st|nd|rd)/,
        ordinal: function (number) {
            var b = number % 10,
                output = (toInt(number % 100 / 10) === 1) ? "th" :
                (b === 1) ? "st" :
                (b === 2) ? "nd" :
                (b === 3) ? "rd" : "th";
            return number + output;
        }
    });

    // Side effect imports
    utils_hooks__hooks.lang = deprecate("moment.lang is deprecated. Use moment.locale instead.", locale_locales__getSetGlobalLocale);
    utils_hooks__hooks.langData = deprecate("moment.langData is deprecated. Use moment.localeData instead.", locale_locales__getLocale);

    var mathAbs = Math.abs;

    function duration_abs__abs () {
        var data           = this._data;

        this._milliseconds = mathAbs(this._milliseconds);
        this._days         = mathAbs(this._days);
        this._months       = mathAbs(this._months);

        data.milliseconds  = mathAbs(data.milliseconds);
        data.seconds       = mathAbs(data.seconds);
        data.minutes       = mathAbs(data.minutes);
        data.hours         = mathAbs(data.hours);
        data.months        = mathAbs(data.months);
        data.years         = mathAbs(data.years);

        return this;
    }

    function duration_add_subtract__addSubtract (duration, input, value, direction) {
        var other = create__createDuration(input, value);

        duration._milliseconds += direction * other._milliseconds;
        duration._days         += direction * other._days;
        duration._months       += direction * other._months;

        return duration._bubble();
    }

    // supports only 2.0-style add(1, 's') or add(duration)
    function duration_add_subtract__add (input, value) {
        return duration_add_subtract__addSubtract(this, input, value, 1);
    }

    // supports only 2.0-style subtract(1, 's') or subtract(duration)
    function duration_add_subtract__subtract (input, value) {
        return duration_add_subtract__addSubtract(this, input, value, -1);
    }

    function bubble () {
        var milliseconds = this._milliseconds;
        var days         = this._days;
        var months       = this._months;
        var data         = this._data;
        var seconds, minutes, hours, years = 0;

        // The following code bubbles up values, see the tests for
        // examples of what that means.
        data.milliseconds = milliseconds % 1000;

        seconds           = absFloor(milliseconds / 1000);
        data.seconds      = seconds % 60;

        minutes           = absFloor(seconds / 60);
        data.minutes      = minutes % 60;

        hours             = absFloor(minutes / 60);
        data.hours        = hours % 24;

        days += absFloor(hours / 24);

        // Accurately convert days to years, assume start from year 0.
        years = absFloor(daysToYears(days));
        days -= absFloor(yearsToDays(years));

        // 30 days to a month
        // TODO (iskren): Use anchor date (like 1st Jan) to compute this.
        months += absFloor(days / 30);
        days   %= 30;

        // 12 months -> 1 year
        years  += absFloor(months / 12);
        months %= 12;

        data.days   = days;
        data.months = months;
        data.years  = years;

        return this;
    }

    function daysToYears (days) {
        // 400 years have 146097 days (taking into account leap year rules)
        return days * 400 / 146097;
    }

    function yearsToDays (years) {
        // years * 365 + absFloor(years / 4) -
        //     absFloor(years / 100) + absFloor(years / 400);
        return years * 146097 / 400;
    }

    function as (units) {
        var days;
        var months;
        var milliseconds = this._milliseconds;

        units = normalizeUnits(units);

        if (units === "month" || units === "year") {
            days   = this._days   + milliseconds / 86400000;
            months = this._months + daysToYears(days) * 12;
            return units === "month" ? months : months / 12;
        } else {
            // handle milliseconds separately because of floating point math errors (issue #1867)
            days = this._days + Math.round(yearsToDays(this._months / 12));
            switch (units) {
                case "week"   : return days / 7            + milliseconds / 604800000;
                case "day"    : return days                + milliseconds / 86400000;
                case "hour"   : return days * 24           + milliseconds / 3600000;
                case "minute" : return days * 24 * 60      + milliseconds / 60000;
                case "second" : return days * 24 * 60 * 60 + milliseconds / 1000;
                // Math.floor prevents floating point math errors here
                case "millisecond": return Math.floor(days * 24 * 60 * 60 * 1000) + milliseconds;
                default: throw new Error("Unknown unit " + units);
            }
        }
    }

    // TODO: Use this.as('ms')?
    function duration_as__valueOf () {
        return (
            this._milliseconds +
            this._days * 86400000 +
            (this._months % 12) * 2592000000 +
            toInt(this._months / 12) * 31536000000
        );
    }

    function makeAs (alias) {
        return function () {
            return this.as(alias);
        };
    }

    var asMilliseconds = makeAs("ms");
    var asSeconds      = makeAs("s");
    var asMinutes      = makeAs("m");
    var asHours        = makeAs("h");
    var asDays         = makeAs("d");
    var asWeeks        = makeAs("w");
    var asMonths       = makeAs("M");
    var asYears        = makeAs("y");

    function duration_get__get (units) {
        units = normalizeUnits(units);
        return this[units + "s"]();
    }

    function makeGetter(name) {
        return function () {
            return this._data[name];
        };
    }

    var duration_get__milliseconds = makeGetter("milliseconds");
    var seconds      = makeGetter("seconds");
    var minutes      = makeGetter("minutes");
    var hours        = makeGetter("hours");
    var days         = makeGetter("days");
    var months       = makeGetter("months");
    var years        = makeGetter("years");

    function weeks () {
        return absFloor(this.days() / 7);
    }

    var round = Math.round;
    var thresholds = {
        s: 45,  // seconds to minute
        m: 45,  // minutes to hour
        h: 22,  // hours to day
        d: 26,  // days to month
        M: 11   // months to year
    };

    // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
    function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
        return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
    }

    function duration_humanize__relativeTime (posNegDuration, withoutSuffix, locale) {
        var duration = create__createDuration(posNegDuration).abs();
        var seconds  = round(duration.as("s"));
        var minutes  = round(duration.as("m"));
        var hours    = round(duration.as("h"));
        var days     = round(duration.as("d"));
        var months   = round(duration.as("M"));
        var years    = round(duration.as("y"));

        var a = seconds < thresholds.s && ["s", seconds]  ||
                minutes === 1          && ["m"]           ||
                minutes < thresholds.m && ["mm", minutes] ||
                hours   === 1          && ["h"]           ||
                hours   < thresholds.h && ["hh", hours]   ||
                days    === 1          && ["d"]           ||
                days    < thresholds.d && ["dd", days]    ||
                months  === 1          && ["M"]           ||
                months  < thresholds.M && ["MM", months]  ||
                years   === 1          && ["y"]           || ["yy", years];

        a[2] = withoutSuffix;
        a[3] = +posNegDuration > 0;
        a[4] = locale;
        return substituteTimeAgo.apply(null, a);
    }

    // This function allows you to set a threshold for relative time strings
    function duration_humanize__getSetRelativeTimeThreshold (threshold, limit) {
        if (thresholds[threshold] === undefined) {
            return false;
        }
        if (limit === undefined) {
            return thresholds[threshold];
        }
        thresholds[threshold] = limit;
        return true;
    }

    function humanize (withSuffix) {
        var locale = this.localeData();
        var output = duration_humanize__relativeTime(this, !withSuffix, locale);

        if (withSuffix) {
            output = locale.pastFuture(+this, output);
        }

        return locale.postformat(output);
    }

    var iso_string__abs = Math.abs;

    function iso_string__toISOString() {
        // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
        var Y = iso_string__abs(this.years());
        var M = iso_string__abs(this.months());
        var D = iso_string__abs(this.days());
        var h = iso_string__abs(this.hours());
        var m = iso_string__abs(this.minutes());
        var s = iso_string__abs(this.seconds() + this.milliseconds() / 1000);
        var total = this.asSeconds();

        if (!total) {
            // this is the same as C#'s (Noda) and python (isodate)...
            // but not other JS (goog.date)
            return "P0D";
        }

        return (total < 0 ? "-" : "") +
            "P" +
            (Y ? Y + "Y" : "") +
            (M ? M + "M" : "") +
            (D ? D + "D" : "") +
            ((h || m || s) ? "T" : "") +
            (h ? h + "H" : "") +
            (m ? m + "M" : "") +
            (s ? s + "S" : "");
    }

    var duration_prototype__proto = Duration.prototype;

    duration_prototype__proto.abs            = duration_abs__abs;
    duration_prototype__proto.add            = duration_add_subtract__add;
    duration_prototype__proto.subtract       = duration_add_subtract__subtract;
    duration_prototype__proto.as             = as;
    duration_prototype__proto.asMilliseconds = asMilliseconds;
    duration_prototype__proto.asSeconds      = asSeconds;
    duration_prototype__proto.asMinutes      = asMinutes;
    duration_prototype__proto.asHours        = asHours;
    duration_prototype__proto.asDays         = asDays;
    duration_prototype__proto.asWeeks        = asWeeks;
    duration_prototype__proto.asMonths       = asMonths;
    duration_prototype__proto.asYears        = asYears;
    duration_prototype__proto.valueOf        = duration_as__valueOf;
    duration_prototype__proto._bubble        = bubble;
    duration_prototype__proto.get            = duration_get__get;
    duration_prototype__proto.milliseconds   = duration_get__milliseconds;
    duration_prototype__proto.seconds        = seconds;
    duration_prototype__proto.minutes        = minutes;
    duration_prototype__proto.hours          = hours;
    duration_prototype__proto.days           = days;
    duration_prototype__proto.weeks          = weeks;
    duration_prototype__proto.months         = months;
    duration_prototype__proto.years          = years;
    duration_prototype__proto.humanize       = humanize;
    duration_prototype__proto.toISOString    = iso_string__toISOString;
    duration_prototype__proto.toString       = iso_string__toISOString;
    duration_prototype__proto.toJSON         = iso_string__toISOString;
    duration_prototype__proto.locale         = locale;
    duration_prototype__proto.localeData     = localeData;

    // Deprecations
    duration_prototype__proto.toIsoString = deprecate("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)", iso_string__toISOString);
    duration_prototype__proto.lang = lang;

    // Side effect imports

    addFormatToken("X", 0, 0, "unix");
    addFormatToken("x", 0, 0, "valueOf");

    // PARSING

    addRegexToken("x", matchSigned);
    addRegexToken("X", matchTimestamp);
    addParseToken("X", function (input, array, config) {
        config._d = new Date(parseFloat(input, 10) * 1000);
    });
    addParseToken("x", function (input, array, config) {
        config._d = new Date(toInt(input));
    });

    // Side effect imports


    utils_hooks__hooks.version = "2.10.2";

    setHookCallback(local__createLocal);

    utils_hooks__hooks.fn                    = momentPrototype;
    utils_hooks__hooks.min                   = min;
    utils_hooks__hooks.max                   = max;
    utils_hooks__hooks.utc                   = create_utc__createUTC;
    utils_hooks__hooks.unix                  = moment__createUnix;
    utils_hooks__hooks.months                = lists__listMonths;
    utils_hooks__hooks.isDate                = isDate;
    utils_hooks__hooks.locale                = locale_locales__getSetGlobalLocale;
    utils_hooks__hooks.invalid               = valid__createInvalid;
    utils_hooks__hooks.duration              = create__createDuration;
    utils_hooks__hooks.isMoment              = isMoment;
    utils_hooks__hooks.weekdays              = lists__listWeekdays;
    utils_hooks__hooks.parseZone             = moment__createInZone;
    utils_hooks__hooks.localeData            = locale_locales__getLocale;
    utils_hooks__hooks.isDuration            = isDuration;
    utils_hooks__hooks.monthsShort           = lists__listMonthsShort;
    utils_hooks__hooks.weekdaysMin           = lists__listWeekdaysMin;
    utils_hooks__hooks.defineLocale          = defineLocale;
    utils_hooks__hooks.weekdaysShort         = lists__listWeekdaysShort;
    utils_hooks__hooks.normalizeUnits        = normalizeUnits;
    utils_hooks__hooks.relativeTimeThreshold = duration_humanize__getSetRelativeTimeThreshold;

    var _moment = utils_hooks__hooks;

    return _moment;
}));
//! moment.js locale configuration
//! locale : canadian english (en-ca)
//! author : Jonathan Abourbih : https://github.com/jonbca

(function (global, factory) {
    typeof exports === "object" && typeof module !== "undefined" ? factory(require("../moment")) :
    typeof define === "function" && define.amd ? define(["moment"], factory) :
    factory(global.moment);
}(this, function (moment) {
    "use strict";


    var en_ca = moment.defineLocale("en-ca", {
        months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
        monthsShort: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
        weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
        weekdaysShort: "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
        weekdaysMin: "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
        longDateFormat: {
            LT: "h:mm A",
            LTS: "h:mm:ss A",
            L: "YYYY-MM-DD",
            LL: "D MMMM, YYYY",
            LLL: "D MMMM, YYYY LT",
            LLLL: "dddd, D MMMM, YYYY LT"
        },
        calendar: {
            sameDay: "[Today at] LT",
            nextDay: "[Tomorrow at] LT",
            nextWeek: "dddd [at] LT",
            lastDay: "[Yesterday at] LT",
            lastWeek: "[Last] dddd [at] LT",
            sameElse: "L"
        },
        relativeTime: {
            future: "in %s",
            past: "%s ago",
            s: "a few seconds",
            m: "a minute",
            mm: "%d minutes",
            h: "an hour",
            hh: "%d hours",
            d: "a day",
            dd: "%d days",
            M: "a month",
            MM: "%d months",
            y: "a year",
            yy: "%d years"
        },
        ordinalParse: /\d{1,2}(st|nd|rd|th)/,
        ordinal: function (number) {
            var b = number % 10,
                output = (~~(number % 100 / 10) === 1) ? "th" :
                (b === 1) ? "st" :
                (b === 2) ? "nd" :
                (b === 3) ? "rd" : "th";
            return number + output;
        }
    });

    return en_ca;
}));
//! moment.js locale configuration
//! locale : great britain english (en-gb)
//! author : Chris Gedrim : https://github.com/chrisgedrim

(function (global, factory) {
    typeof exports === "object" && typeof module !== "undefined" ? factory(require("../moment")) :
    typeof define === "function" && define.amd ? define(["moment"], factory) :
    factory(global.moment);
}(this, function (moment) {
    "use strict";


    var en_gb = moment.defineLocale("en-gb", {
        months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
        monthsShort: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
        weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
        weekdaysShort: "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
        weekdaysMin: "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
        longDateFormat: {
            LT: "HH:mm",
            LTS: "HH:mm:ss",
            L: "DD/MM/YYYY",
            LL: "D MMMM YYYY",
            LLL: "D MMMM YYYY LT",
            LLLL: "dddd, D MMMM YYYY LT"
        },
        calendar: {
            sameDay: "[Today at] LT",
            nextDay: "[Tomorrow at] LT",
            nextWeek: "dddd [at] LT",
            lastDay: "[Yesterday at] LT",
            lastWeek: "[Last] dddd [at] LT",
            sameElse: "L"
        },
        relativeTime: {
            future: "in %s",
            past: "%s ago",
            s: "a few seconds",
            m: "a minute",
            mm: "%d minutes",
            h: "an hour",
            hh: "%d hours",
            d: "a day",
            dd: "%d days",
            M: "a month",
            MM: "%d months",
            y: "a year",
            yy: "%d years"
        },
        ordinalParse: /\d{1,2}(st|nd|rd|th)/,
        ordinal: function (number) {
            var b = number % 10,
                output = (~~(number % 100 / 10) === 1) ? "th" :
                (b === 1) ? "st" :
                (b === 2) ? "nd" :
                (b === 3) ? "rd" : "th";
            return number + output;
        },
        week: {
            dow: 1, // Monday is the first day of the week.
            doy: 4  // The week that contains Jan 4th is the first week of the year.
        }
    });

    return en_gb;
}));
//! moment.js locale configuration
//! locale : canadian french (fr-ca)
//! author : Jonathan Abourbih : https://github.com/jonbca

(function (global, factory) {
    typeof exports === "object" && typeof module !== "undefined" ? factory(require("../moment")) :
    typeof define === "function" && define.amd ? define(["moment"], factory) :
    factory(global.moment);
}(this, function (moment) {
    "use strict";


    var fr_ca = moment.defineLocale("fr-ca", {
        months: "janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),
        monthsShort: "janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),
        weekdays: "dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),
        weekdaysShort: "dim._lun._mar._mer._jeu._ven._sam.".split("_"),
        weekdaysMin: "Di_Lu_Ma_Me_Je_Ve_Sa".split("_"),
        longDateFormat: {
            LT: "HH:mm",
            LTS: "LT:ss",
            L: "YYYY-MM-DD",
            LL: "D MMMM YYYY",
            LLL: "D MMMM YYYY LT",
            LLLL: "dddd D MMMM YYYY LT"
        },
        calendar: {
            sameDay: "[Aujourd'hui à] LT",
            nextDay: "[Demain à] LT",
            nextWeek: "dddd [à] LT",
            lastDay: "[Hier à] LT",
            lastWeek: "dddd [dernier à] LT",
            sameElse: "L"
        },
        relativeTime: {
            future: "dans %s",
            past: "il y a %s",
            s: "quelques secondes",
            m: "une minute",
            mm: "%d minutes",
            h: "une heure",
            hh: "%d heures",
            d: "un jour",
            dd: "%d jours",
            M: "un mois",
            MM: "%d mois",
            y: "un an",
            yy: "%d ans"
        },
        ordinalParse: /\d{1,2}(er|)/,
        ordinal: function (number) {
            return number + (number === 1 ? "er" : "");
        }
    });

    return fr_ca;
}));
//! moment.js locale configuration
//! locale : french (fr)
//! author : John Fischer : https://github.com/jfroffice

(function (global, factory) {
    typeof exports === "object" && typeof module !== "undefined" ? factory(require("../moment")) :
    typeof define === "function" && define.amd ? define(["moment"], factory) :
    factory(global.moment);
}(this, function (moment) {
    "use strict";


    var fr = moment.defineLocale("fr", {
        months: "janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),
        monthsShort: "janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),
        weekdays: "dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),
        weekdaysShort: "dim._lun._mar._mer._jeu._ven._sam.".split("_"),
        weekdaysMin: "Di_Lu_Ma_Me_Je_Ve_Sa".split("_"),
        longDateFormat: {
            LT: "HH:mm",
            LTS: "LT:ss",
            L: "DD/MM/YYYY",
            LL: "D MMMM YYYY",
            LLL: "D MMMM YYYY LT",
            LLLL: "dddd D MMMM YYYY LT"
        },
        calendar: {
            sameDay: "[Aujourd'hui à] LT",
            nextDay: "[Demain à] LT",
            nextWeek: "dddd [à] LT",
            lastDay: "[Hier à] LT",
            lastWeek: "dddd [dernier à] LT",
            sameElse: "L"
        },
        relativeTime: {
            future: "dans %s",
            past: "il y a %s",
            s: "quelques secondes",
            m: "une minute",
            mm: "%d minutes",
            h: "une heure",
            hh: "%d heures",
            d: "un jour",
            dd: "%d jours",
            M: "un mois",
            MM: "%d mois",
            y: "un an",
            yy: "%d ans"
        },
        ordinalParse: /\d{1,2}(er|)/,
        ordinal: function (number) {
            return number + (number === 1 ? "er" : "");
        },
        week: {
            dow: 1, // Monday is the first day of the week.
            doy: 4  // The week that contains Jan 4th is the first week of the year.
        }
    });

    return fr;
}));
/*
 DATE & TIME USAGE:
 var dateTime = new (Helpers('date-time'));
 console.log(dateTime.moment().format());
*/
var $__Object$defineProperties = Object.defineProperties;

var DateTime = function() {
    "use strict";

    function DateTime(config) {
        var defaultConfig = {
			locale: null
		};

        this.config = $.extend({}, defaultConfig, config);

        // set language (try to grab from the page) but fallback to 'en' just in case.
        this.language = ($("body").data("culture-code")) ? $("body").data("culture-code").toLowerCase() : "en-gb";
        this.config.locale ? moment.locale(this.config.locale) : moment.locale(this.language);

        // store instance of moment.js
        this._m = moment;

        /*setTimeout(() => {
            // delete global access from window. Removed for debug
            delete window.moment;
        });*/;
    }

    $__Object$defineProperties(DateTime.prototype, {
        formatDate: {
            value: function(date, format) {
                return this.moment(date).format(format);
            },

            enumerable: false,
            writable: true
        },

        moment: {
            value: function(value) {
                return this._m(value);
            },

            enumerable: false,
            writable: true
        },

        padTwodigits: {
            value: function(value) {
                value = parseInt(value);
                return (value < 10) ? "0" + value.toString() : value.toString();
            },

            enumerable: false,
            writable: true
        },

        padTime: {
            value: function(t) {
                var time = t.split(":");
                return this.padTwodigits(time[0])+ ":" + this.padTwodigits(time[1]);
            },

            enumerable: false,
            writable: true
        }
    });

    return DateTime;
}();

return DateTime;
});
}).apply(window);/**!!<[helper.date-time]!!**/
/**!![helper.dealer-locator]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_ctaLinks"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "    <div class=\"test-drive\">\n        <a class=\"cta link\" href=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.CTA : stack1)) != null ? stack1.TestDrive : stack1), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.details : stack1)) != null ? stack1.label : stack1)) != null ? stack1.testdrive : stack1), depth0))
    + "</a>\n    </div>\n";
},"3":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "    <div class=\"quote\">\n        <a class=\"cta link\" href=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.CTA : stack1)) != null ? stack1.Quote : stack1), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.details : stack1)) != null ? stack1.label : stack1)) != null ? stack1.quote : stack1), depth0))
    + "</a>\n    </div>\n";
},"5":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "    <div class=\"configuration\">\n        <a class=\"cta link\" href=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.CTA : stack1)) != null ? stack1.Service : stack1), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.details : stack1)) != null ? stack1.label : stack1)) != null ? stack1.service : stack1), depth0))
    + "</a>\n    </div>\n";
},"7":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "    <div class=\"catalogue\">\n        <a class=\"cta link\" href=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.CTA : stack1)) != null ? stack1.Brochure : stack1), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.details : stack1)) != null ? stack1.label : stack1)) != null ? stack1.brochure : stack1), depth0))
    + "</a>\n    </div>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "<div class=\"helper-ctas\">\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.CTA : stack1)) != null ? stack1.TestDrive : stack1)) != null ? stack1.length : stack1), ">", 0, {"name":"compare","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.CTA : stack1)) != null ? stack1.Quote : stack1)) != null ? stack1.length : stack1), ">", 0, {"name":"compare","hash":{},"fn":this.program(3, data),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.CTA : stack1)) != null ? stack1.Service : stack1)) != null ? stack1.length : stack1), ">", 0, {"name":"compare","hash":{},"fn":this.program(5, data),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.CTA : stack1)) != null ? stack1.Brochure : stack1)) != null ? stack1.length : stack1), ">", 0, {"name":"compare","hash":{},"fn":this.program(7, data),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</div>";
},"useData":true});
this["templates"]["_dealerBtn"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "    <a href=\"#\" class=\"cta-btn close\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.button : stack1)) != null ? stack1.selected : stack1), depth0))
    + "</a>\n";
},"3":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "    <a href=\"#\" class=\"cta-btn\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.button : stack1)) != null ? stack1.unselected : stack1), depth0))
    + "</a>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, helperMissing=helpers.helperMissing;
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, (depth0 != null ? depth0.active : depth0), "===", true, {"name":"compare","hash":{},"fn":this.program(1, data),"inverse":this.program(3, data),"data":data}));
  if (stack1 != null) { return stack1; }
  else { return ''; }
  },"useData":true});
this["templates"]["_details"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helperMissing=helpers.helperMissing, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "\n<!-- START Dealer Details -->\n<div class=\"detail-inner\">\n\n    <div class=\"detail-content\">\n\n        <div class=\"wrapper\">\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.OpeningTimes : stack1)) != null ? stack1.length : stack1), ">", 0, {"name":"compare","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n";
  stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.CTA : stack1), {"name":"if","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Awards : stack1)) != null ? stack1.length : stack1), ">", 0, {"name":"compare","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "        </div>\n\n    </div>\n\n    <div class=\"detail-thumb\">\n        <a class=\"res-1024-cols-12\" href=\"#\">\n            <span class=\"cta-btn show more\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.details : stack1)) != null ? stack1.button : stack1)) != null ? stack1.more : stack1), depth0))
    + "</span>\n            <span class=\"cta-btn less\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.details : stack1)) != null ? stack1.button : stack1)) != null ? stack1.less : stack1), depth0))
    + "</span>\n        </a>\n    </div>\n\n</div>\n<!-- END Dealer Details -->\n\n";
},"2":function(depth0,helpers,partials,data) {
  var stack1, buffer = "            <!-- START opening times -->\n            <div class=\"dealer-times\">\n";
  stack1 = this.invokePartial(partials._openingTimes, '                ', '_openingTimes', depth0, {
    'services': ((depth0 != null ? depth0.services : depth0)),
    'weekday': (((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Weekday : stack1)),
    'language': ((depth0 != null ? depth0.language : depth0))
  }, helpers, partials, data);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "            </div>\n            <!-- END opening times -->\n";
},"4":function(depth0,helpers,partials,data) {
  var stack1, buffer = "            <!-- START CTA's -->\n            <div class=\"dealer-cta\">\n";
  stack1 = this.invokePartial(partials._ctaLinks, '                ', '_ctaLinks', depth0, {
    'language': ((depth0 != null ? depth0.language : depth0))
  }, helpers, partials, data);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "            </div>\n            <!-- END CTA's -->\n";
},"6":function(depth0,helpers,partials,data) {
  var stack1, buffer = "            <!-- START awards -->\n            <div class=\"dealer-awards\">\n";
  stack1 = helpers.each.call(depth0, ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Awards : stack1), {"name":"each","hash":{},"fn":this.program(7, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "            </div>\n            <!-- END awards -->\n";
},"7":function(depth0,helpers,partials,data) {
  var stack1, buffer = "";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.BadgeUrl : depth0), {"name":"if","hash":{},"fn":this.program(8, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"8":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                <div class=\"res-1024-cols-4 award\">\n                    <div class=\"thumbnail\">\n                        <img src=\""
    + escapeExpression(lambda((depth0 != null ? depth0.BadgeUrl : depth0), depth0))
    + "\" alt=\""
    + escapeExpression(lambda((depth0 != null ? depth0.Title : depth0), depth0))
    + "\" />\n                    </div>\n                </div>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, helperMissing=helpers.helperMissing;
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.hasDetail : stack1), "===", true, {"name":"compare","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data}));
  if (stack1 != null) { return stack1; }
  else { return ''; }
  },"usePartial":true,"useData":true});
this["templates"]["_location"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "            <p>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.location : stack1)) != null ? stack1.label : stack1)) != null ? stack1.title : stack1), depth0))
    + " <span>"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.position : depth0)) != null ? stack1.formatted_address : stack1), depth0))
    + "</span><br />\n                <a href=\"#\" class=\"cta-btn dealer-refresh disabled\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.location : stack1)) != null ? stack1.label : stack1)) != null ? stack1.button : stack1), depth0))
    + "</a>\n            </p>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "<div class=\"inner\">\n    <div class=\"res-1024-cols-6 we-think\">\n";
  stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 != null ? depth0.position : depth0)) != null ? stack1.formatted_address : stack1), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "    </div>\n    <div class=\"res-1024-cols-6 region-reset\">\n        <p>"
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.regionresult : stack1), depth0))
    + " <span class=\"region-name\"></span><br />\n             <a href=\"#\" class=\"cta-btn dealer-refresh dealer-location disabled\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.removerestriction : stack1), depth0))
    + "</a>\n        </p>\n    </div>\n    <div class=\"res-1024-cols-6 choice\">\n        <p>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.location : stack1)) != null ? stack1.label : stack1)) != null ? stack1.query : stack1), depth0))
    + "<br />\n            <a href=\"#tab-postcode\" class=\"cta search-postcode\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.location : stack1)) != null ? stack1.label : stack1)) != null ? stack1.action2 : stack1), depth0))
    + "</a>\n        </p>\n    </div>\n    \n</div>";
},"useData":true});
this["templates"]["_map"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  return "<div class=\"map-wrapper\">\n    <div class=\"map-overlay\"></div>\n    <div class=\"map-container\" map-streetview-active=\"true\"></div>\n</div>";
  },"useData":true});
this["templates"]["_mapOverlay"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<span>"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Distance : stack1), depth0))
    + " km</span>";
},"3":function(depth0,helpers,partials,data) {
  var stack1, buffer = "			<p>\n				";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Address1 : depth0), {"name":"if","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n				";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Address2 : depth0), {"name":"if","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n				";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.City : depth0), {"name":"if","hash":{},"fn":this.program(8, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n				";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Zip : depth0), {"name":"if","hash":{},"fn":this.program(10, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n			</p>\n";
},"4":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.Address1 : depth0), depth0))
    + ", ";
},"6":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.Address2 : depth0), depth0))
    + ", ";
},"8":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.City : depth0), depth0))
    + ", ";
},"10":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.Zip : depth0), depth0))
    + " ";
},"12":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<li><a class=\"cta-btn telephone\" href=\"tel:"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.PhoneNumber : stack1), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.PhoneNumber : stack1), depth0))
    + "</a></li>";
},"14":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<li><a class=\"cta-btn website\" href=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.WebsiteUrl : stack1), depth0))
    + "\" target=\"_blank\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.label : stack1)) != null ? stack1.website : stack1), depth0))
    + "</a></li>";
},"16":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<li><a class=\"cta-btn google\" href=\"https://www.google.com/maps/dir//"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Coordinates : stack1)) != null ? stack1.Latitude : stack1), depth0))
    + ","
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Coordinates : stack1)) != null ? stack1.Longitude : stack1), depth0))
    + "\" target=\"_blank\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.label : stack1)) != null ? stack1.google : stack1), depth0))
    + "</a></li>";
},"18":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "            <!-- START Dealer Details -->\n            <div class=\"detail-inner active\">\n\n                <div class=\"detail-content\">\n\n                    <div class=\"wrapper\">\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.OpeningTimes : stack1)) != null ? stack1.length : stack1), ">", 0, {"name":"compare","hash":{},"fn":this.program(19, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n";
  stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.CTA : stack1), {"name":"if","hash":{},"fn":this.program(31, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                    </div>\n\n                </div>\n\n            </div>\n            <!-- END Dealer Details -->\n";
},"19":function(depth0,helpers,partials,data,depths) {
  var stack1, buffer = "                            <!-- START opening times -->\n                            <div class=\"dealer-times\">\n";
  stack1 = helpers.each.call(depth0, ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.OpeningTimes : stack1), {"name":"each","hash":{},"fn":this.program(20, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                            </div>\n                            <!-- END opening times -->\n";
},"20":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, (depth0 != null ? depth0.ServiceType : depth0), "===", "Parts", {"name":"compare","hash":{},"fn":this.program(21, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, (depth0 != null ? depth0.ServiceType : depth0), "===", "Sales", {"name":"compare","hash":{},"fn":this.program(27, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, (depth0 != null ? depth0.ServiceType : depth0), "===", "Service", {"name":"compare","hash":{},"fn":this.program(29, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n";
},"21":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = (depths[2] != null ? depths[2].services : depths[2])) != null ? stack1.parts : stack1), "===", true, {"name":"compare","hash":{},"fn":this.program(22, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"22":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, helperMissing=helpers.helperMissing, buffer = "                                            <li class=\"times-inner\">\n                                                <div class=\"times-thumb\">\n                                                    <div class=\"inner\">\n                                                        <div class=\"res-1024-cols-3\">\n                                                            <h4>"
    + escapeExpression(lambda((depth0 != null ? depth0.ServiceType : depth0), depth0))
    + "</h4>\n                                                        </div>\n                                                        <div class=\"res-1024-cols-9\">\n															";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, (depth0 != null ? depth0.Today : depth0), "===", false, {"name":"compare","hash":{},"fn":this.program(23, data, depths),"inverse":this.program(25, data, depths),"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n                                                        </div>\n                                                    </div>\n                                                </div>\n                                            </li>\n";
},"23":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depths[4] != null ? depths[4].language : depths[4])) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.details : stack1)) != null ? stack1.datetime : stack1)) != null ? stack1.closed : stack1), depth0));
  },"25":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depths[4] != null ? depths[4].language : depths[4])) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.details : stack1)) != null ? stack1.datetime : stack1)) != null ? stack1.open : stack1), depth0))
    + " "
    + escapeExpression(lambda((depth0 != null ? depth0.Today : depth0), depth0));
},"27":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = (depths[2] != null ? depths[2].services : depths[2])) != null ? stack1.sales : stack1), "===", true, {"name":"compare","hash":{},"fn":this.program(22, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"29":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = (depths[2] != null ? depths[2].services : depths[2])) != null ? stack1.service : stack1), "===", true, {"name":"compare","hash":{},"fn":this.program(22, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"31":function(depth0,helpers,partials,data) {
  var stack1, buffer = "                            <!-- START CTA's -->\n                            <div class=\"dealer-cta\">\n";
  stack1 = this.invokePartial(partials._ctaLinks, '								', '_ctaLinks', depth0, {
    'language': ((depth0 != null ? depth0.language : depth0))
  }, helpers, partials, data);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                            </div>\n                            <!-- END CTA's -->\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data,depths) {
  var stack1, helper, lambda=this.lambda, escapeExpression=this.escapeExpression, functionType="function", helperMissing=helpers.helperMissing, buffer = "<div class=\"overlay-inner\" data-id='"
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.DealerId : stack1), depth0))
    + "' data-index='"
    + escapeExpression(((helper = (helper = helpers.label || (depth0 != null ? depth0.label : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"label","hash":{},"data":data}) : helper)))
    + "'>\n\n	<header class=\"container\">\n		<div class=\"res-1024-cols-12\">\n\n			<div class=\"marker\">\n				<div class=\"image\">"
    + escapeExpression(((helper = (helper = helpers.label || (depth0 != null ? depth0.label : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"label","hash":{},"data":data}) : helper)))
    + "</div>\n                ";
  stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Distance : stack1), {"name":"if","hash":{},"fn":this.program(1, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n			</div>\n			<h5>"
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.DealerName : stack1), depth0))
    + "</h5>\n\n			<a class=\"close\" href=\"#close\">Close</a>\n		</div>\n	</header>\n\n	<div class=\"container dealer-info\">\n\n";
  stack1 = helpers.each.call(depth0, ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Address : stack1), {"name":"each","hash":{},"fn":this.program(3, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n        <ul class=\"dealer-action\">\n			";
  stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.PhoneNumber : stack1), {"name":"if","hash":{},"fn":this.program(12, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n			";
  stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.WebsiteUrl : stack1), {"name":"if","hash":{},"fn":this.program(14, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n			";
  stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Coordinates : stack1)) != null ? stack1.Latitude : stack1), {"name":"if","hash":{},"fn":this.program(16, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n        </ul>\n\n        <div class=\"dealer-preferred\">\n";
  stack1 = this.invokePartial(partials._dealerBtn, '			', '_dealerBtn', depth0, {
    'language': ((depth0 != null ? depth0.language : depth0))
  }, helpers, partials, data);
  if (stack1 != null) { buffer += stack1; }
  buffer += "        </div>\n\n	</div>\n\n    <div class=\"container details\">\n\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.hasDetail : stack1), "===", true, {"name":"compare","hash":{},"fn":this.program(18, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n    </div>\n\n</div>";
},"usePartial":true,"useData":true,"useDepths":true});
this["templates"]["_noResults"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<div class=\"inner\">\n    <div class=\"res-1024-cols-12 no-results\">\n        <h4 class=\"title\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.validation : stack1)) != null ? stack1.empty1 : stack1), depth0))
    + "</h4>\n        <p>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.validation : stack1)) != null ? stack1.empty2 : stack1), depth0))
    + "</p>\n    </div>\n</div>";
},"useData":true});
this["templates"]["_openingTimes"] = Handlebars.template({"1":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, (depth0 != null ? depth0.ServiceType : depth0), "===", "Parts", {"name":"compare","hash":{},"fn":this.program(2, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, (depth0 != null ? depth0.ServiceType : depth0), "===", "Sales", {"name":"compare","hash":{},"fn":this.program(15, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, (depth0 != null ? depth0.ServiceType : depth0), "===", "Service", {"name":"compare","hash":{},"fn":this.program(22, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n";
},"2":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = (depths[2] != null ? depths[2].services : depths[2])) != null ? stack1.parts : stack1), "===", true, {"name":"compare","hash":{},"fn":this.program(3, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"3":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, helperMissing=helpers.helperMissing, buffer = "    <li class=\"times-inner\">\n\n        <div class=\"times-thumb\">\n            <a href=\"#\" class=\"button button-icon\">"
    + escapeExpression(lambda((depth0 != null ? depth0.Service : depth0), depth0))
    + "</a>\n\n            <div class=\"inner\">\n                <div class=\"res-1024-cols-3\">\n                    <h4>"
    + escapeExpression(lambda((depth0 != null ? depth0.Service : depth0), depth0))
    + "</h4>\n                </div>\n                <div class=\"res-1024-cols-9\">\n                    ";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, (depth0 != null ? depth0.Today : depth0), "===", false, {"name":"compare","hash":{},"fn":this.program(4, data, depths),"inverse":this.program(6, data, depths),"data":data}));
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                </div>\n            </div>\n        </div>\n\n        <ul class=\"times-content level-2\">\n            <li>\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.Days : depth0), {"name":"each","hash":{},"fn":this.program(8, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "            </li>\n        </ul>\n    </li>\n";
},"4":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depths[4] != null ? depths[4].language : depths[4])) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.details : stack1)) != null ? stack1.datetime : stack1)) != null ? stack1.closed : stack1), depth0));
  },"6":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return " <span> "
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depths[4] != null ? depths[4].language : depths[4])) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.details : stack1)) != null ? stack1.datetime : stack1)) != null ? stack1.open : stack1), depth0))
    + " </span> "
    + escapeExpression(lambda((depth0 != null ? depth0.Today : depth0), depth0));
},"8":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "\n                <div class=\"days";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.DayMatch : depth0), {"name":"if","hash":{},"fn":this.program(9, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\">\n                    <div class=\"res-1024-cols-5 day\">\n                        "
    + escapeExpression(lambda((depth0 != null ? depth0.Day : depth0), depth0))
    + "\n                    </div>\n\n                    <div class=\"res-1024-cols-7 time\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.SingleOpenCloseTime : depth0), {"name":"if","hash":{},"fn":this.program(11, data),"inverse":this.program(13, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                    </div>\n                </div>\n";
},"9":function(depth0,helpers,partials,data) {
  return " active";
  },"11":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "						"
    + escapeExpression(lambda((depth0 != null ? depth0.FormattedOpenTime : depth0), depth0))
    + "\n";
},"13":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        "
    + escapeExpression(lambda((depth0 != null ? depth0.FormattedOpenTime : depth0), depth0))
    + " - "
    + escapeExpression(lambda((depth0 != null ? depth0.FormattedCloseTime : depth0), depth0))
    + "\n";
},"15":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = (depths[2] != null ? depths[2].services : depths[2])) != null ? stack1.sales : stack1), "===", true, {"name":"compare","hash":{},"fn":this.program(16, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"16":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, helperMissing=helpers.helperMissing, buffer = "    <li class=\"times-inner\">\n\n        <div class=\"times-thumb\">\n            <a href=\"#\" class=\"button button-icon\">"
    + escapeExpression(lambda((depth0 != null ? depth0.Service : depth0), depth0))
    + "</a>\n\n            <div class=\"inner\">\n                <div class=\"res-1024-cols-3\">\n                    <h4>"
    + escapeExpression(lambda((depth0 != null ? depth0.Service : depth0), depth0))
    + "</h4>\n                </div>\n                <div class=\"res-1024-cols-9\">\n                    ";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, (depth0 != null ? depth0.Today : depth0), "===", false, {"name":"compare","hash":{},"fn":this.program(4, data, depths),"inverse":this.program(6, data, depths),"data":data}));
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                </div>\n            </div>\n        </div>\n\n        <ul class=\"times-content level-2\">\n            <li>\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.Days : depth0), {"name":"each","hash":{},"fn":this.program(17, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "            </li>\n        </ul>\n    </li>\n";
},"17":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "                <div class=\"days";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.DayMatch : depth0), {"name":"if","hash":{},"fn":this.program(9, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\">\n                    <div class=\"res-1024-cols-5 day\">\n                        "
    + escapeExpression(lambda((depth0 != null ? depth0.Day : depth0), depth0))
    + "\n                    </div>\n\n                    <div class=\"res-1024-cols-7 time\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.SingleOpenCloseTime : depth0), {"name":"if","hash":{},"fn":this.program(18, data),"inverse":this.program(20, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                    </div>\n                </div>\n";
},"18":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                            "
    + escapeExpression(lambda((depth0 != null ? depth0.FormattedOpenTime : depth0), depth0))
    + "\n";
},"20":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                            "
    + escapeExpression(lambda((depth0 != null ? depth0.FormattedOpenTime : depth0), depth0))
    + " - "
    + escapeExpression(lambda((depth0 != null ? depth0.FormattedCloseTime : depth0), depth0))
    + "\n";
},"22":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = (depths[2] != null ? depths[2].services : depths[2])) != null ? stack1.service : stack1), "===", true, {"name":"compare","hash":{},"fn":this.program(16, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data,depths) {
  var stack1, buffer = "<!-- START Opening Times -->\n<ul class=\"times-accordion level-1\">\n\n";
  stack1 = helpers.each.call(depth0, ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.OpeningTimes : stack1), {"name":"each","hash":{},"fn":this.program(1, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n</ul>\n<!-- END Opening Times -->";
},"useData":true,"useDepths":true});
this["templates"]["_results"] = Handlebars.template({"1":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, helperMissing=helpers.helperMissing, buffer = "\n    <div class=\"res-1024-cols-6 list\" data-total=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.pg : depth0)) != null ? stack1.totalResults : stack1), depth0))
    + "\" data-per-page=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.pg : depth0)) != null ? stack1.perPage : stack1), depth0))
    + "\" data-page=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.pg : depth0)) != null ? stack1.currentPage : stack1), depth0))
    + "\" data-pages=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.pg : depth0)) != null ? stack1.pagesTotal : stack1), depth0))
    + "\">\n\n        <h4 class=\"heading\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.title : stack1), depth0))
    + "</h4>\n\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.dealers : depth0), {"name":"each","hash":{},"fn":this.program(2, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n        <div class=\"pagination\">\n";
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = (depth0 != null ? depth0.pg : depth0)) != null ? stack1.currentPage : stack1), ">", 1, {"name":"compare","hash":{},"fn":this.program(24, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = (depth0 != null ? depth0.pg : depth0)) != null ? stack1.currentPage : stack1), "<", ((stack1 = (depth0 != null ? depth0.pg : depth0)) != null ? stack1.pagesTotal : stack1), {"name":"compare","hash":{},"fn":this.program(26, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  buffer += "        </div>\n\n    </div>\n\n    <div class=\"res-1024-cols-6 map\">\n";
  stack1 = this.invokePartial(partials._map, '        ', '_map', depth0, {
    'services': ((depths[1] != null ? depths[1].services : depths[1])),
    'language': ((depths[2] != null ? depths[2].language : depths[2]))
  }, helpers, partials, data);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "    </div>\n\n";
},"2":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "        <article data-id='"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.DealerId : stack1), depth0))
    + "' data-index=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Index : stack1), depth0))
    + "\">\n\n            <div class=\"dealer-preferred\">\n";
  stack1 = this.invokePartial(partials._dealerBtn, '                ', '_dealerBtn', depth0, {
    'language': ((depths[2] != null ? depths[2].language : depths[2]))
  }, helpers, partials, data);
  if (stack1 != null) { buffer += stack1; }
  buffer += "            </div>\n\n            <header class=\"container\">\n                <div class=\"res-1024-cols-12\">\n                    <a href=\"#\" class=\"marker\" title=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.DealerName : stack1), depth0))
    + "\">\n                        <div class=\"image\">"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Index : stack1), depth0))
    + "</div>\n                        ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Distance : depth0), {"name":"if","hash":{},"fn":this.program(3, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                    </a>\n";
  stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.WebsiteUrl : stack1), {"name":"if","hash":{},"fn":this.program(5, data, depths),"inverse":this.program(7, data, depths),"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "                </div>\n            </header>\n\n            <div class=\"container dealer-info\">\n";
  stack1 = helpers.each.call(depth0, ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Address : stack1), {"name":"each","hash":{},"fn":this.program(9, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                <ul class=\"dealer-action\">\n                    ";
  stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.PhoneNumber : stack1), {"name":"if","hash":{},"fn":this.program(18, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                    ";
  stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.WebsiteUrl : stack1), {"name":"if","hash":{},"fn":this.program(20, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                    ";
  stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Coordinates : stack1)) != null ? stack1.Latitude : stack1), {"name":"if","hash":{},"fn":this.program(22, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                </ul>\n            </div>\n\n            <div class=\"container details\">\n";
  stack1 = this.invokePartial(partials._details, '                ', '_details', depth0, {
    'services': ((depths[2] != null ? depths[2].services : depths[2])),
    'language': ((depths[2] != null ? depths[2].language : depths[2]))
  }, helpers, partials, data);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "            </div>\n\n        </article>\n";
},"3":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<span>"
    + escapeExpression(lambda((depth0 != null ? depth0.Distance : depth0), depth0))
    + " km</span>";
},"5":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        <h5><a href=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.WebsiteUrl : stack1), depth0))
    + "\" target=\"_blank\">"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.DealerName : stack1), depth0))
    + "</a></h5>\n";
},"7":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        <h5>"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.DealerName : stack1), depth0))
    + "</h5>\n";
},"9":function(depth0,helpers,partials,data) {
  var stack1, buffer = "                <p>\n                    ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Address1 : depth0), {"name":"if","hash":{},"fn":this.program(10, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                    ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Address2 : depth0), {"name":"if","hash":{},"fn":this.program(12, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                    ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.City : depth0), {"name":"if","hash":{},"fn":this.program(14, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                    ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Zip : depth0), {"name":"if","hash":{},"fn":this.program(16, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n                </p>\n";
},"10":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.Address1 : depth0), depth0))
    + ", ";
},"12":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.Address2 : depth0), depth0))
    + ", ";
},"14":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.City : depth0), depth0))
    + ", ";
},"16":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.Zip : depth0), depth0))
    + " ";
},"18":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<li><a class=\"cta-btn telephone\" href=\"tel:"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.PhoneNumber : stack1), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.PhoneNumber : stack1), depth0))
    + "</a></li>";
},"20":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<li><a class=\"cta-btn website\" href=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Contact : stack1)) != null ? stack1['0'] : stack1)) != null ? stack1.WebsiteUrl : stack1), depth0))
    + "\" target=\"_blank\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depths[2] != null ? depths[2].language : depths[2])) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.label : stack1)) != null ? stack1.website : stack1), depth0))
    + "</a></li>";
},"22":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<li><a class=\"cta-btn google\" href=\"https://www.google.com/maps/dir//"
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Coordinates : stack1)) != null ? stack1.Latitude : stack1), depth0))
    + ","
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.Dealer : depth0)) != null ? stack1.Coordinates : stack1)) != null ? stack1.Longitude : stack1), depth0))
    + "\" target=\"_blank\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depths[2] != null ? depths[2].language : depths[2])) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.label : stack1)) != null ? stack1.google : stack1), depth0))
    + "</a></li>";
},"24":function(depth0,helpers,partials,data) {
  var stack1, helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "            <a href=\"#\" data-target=\""
    + escapeExpression(((helpers.math || (depth0 && depth0.math) || helperMissing).call(depth0, ((stack1 = (depth0 != null ? depth0.pg : depth0)) != null ? stack1.currentPage : stack1), "-", 2, {"name":"math","hash":{},"data":data})))
    + "\" class=\"button button-icon-left prev\">"
    + escapeExpression(((helpers.replace || (depth0 && depth0.replace) || helperMissing).call(depth0, ((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.label : stack1)) != null ? stack1.previous : stack1), "%", ((stack1 = ((stack1 = (depth0 != null ? depth0.pagination : depth0)) != null ? stack1['0'] : stack1)) != null ? stack1.perPage : stack1), {"name":"replace","hash":{},"data":data})))
    + "</a>\n";
},"26":function(depth0,helpers,partials,data) {
  var stack1, helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "            <a href=\"#\" data-target=\""
    + escapeExpression(((helpers.math || (depth0 && depth0.math) || helperMissing).call(depth0, ((stack1 = (depth0 != null ? depth0.pg : depth0)) != null ? stack1.currentPage : stack1), "+", 0, {"name":"math","hash":{},"data":data})))
    + "\" class=\"button button-icon next\">\n            "
    + escapeExpression(((helpers.replace || (depth0 && depth0.replace) || helperMissing).call(depth0, ((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.results : stack1)) != null ? stack1.label : stack1)) != null ? stack1.next : stack1), "%", ((stack1 = ((stack1 = (depth0 != null ? depth0.pagination : depth0)) != null ? stack1['0'] : stack1)) != null ? stack1.perPage : stack1), {"name":"replace","hash":{},"data":data})))
    + "</a>\n";
},"28":function(depth0,helpers,partials,data,depths) {
  var stack1, buffer = "\n";
  stack1 = this.invokePartial(partials._noResults, '    ', '_noResults', depth0, {
    'language': ((depths[2] != null ? depths[2].language : depths[2]))
  }, helpers, partials, data);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing;
  stack1 = ((helpers.compare || (depth0 && depth0.compare) || helperMissing).call(depth0, ((stack1 = (depth0 != null ? depth0.dealers : depth0)) != null ? stack1.length : stack1), ">", 0, {"name":"compare","hash":{},"fn":this.program(1, data, depths),"inverse":this.program(28, data, depths),"data":data}));
  if (stack1 != null) { return stack1; }
  else { return ''; }
  },"usePartial":true,"useData":true,"useDepths":true});
this["templates"]["_schedulerOverlay"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "        <div class=\"row\">\n            <div class=\"res-1600-cols-3 res-1024-cols-6\">\n                <div class=\"overlay-header\">\n                    <p>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.scheduler : stack1)) != null ? stack1.label : stack1)) != null ? stack1.current : stack1), depth0))
    + "</p>\n                    <h4>"
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.data : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.DealerName : stack1), depth0))
    + "</h4>\n                </div>\n\n";
  stack1 = helpers.each.call(depth0, ((stack1 = ((stack1 = (depth0 != null ? depth0.data : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Address : stack1), {"name":"each","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "            </div>\n            <div class=\"res-1600-cols-3 res-1024-cols-6\">\n                <div class=\"image\"></div>\n                <p class=\"dealer-option\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.scheduler : stack1)) != null ? stack1.label : stack1)) != null ? stack1.option : stack1), depth0))
    + "</p>\n                <p class=\"dealer-description\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.scheduler : stack1)) != null ? stack1.label : stack1)) != null ? stack1.description : stack1), depth0))
    + "</p>\n            </div>\n        </div>\n";
},"2":function(depth0,helpers,partials,data) {
  var stack1, buffer = "                <p class=\"dealer-address\">\n                    ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Address1 : depth0), {"name":"if","hash":{},"fn":this.program(3, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                    ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Address2 : depth0), {"name":"if","hash":{},"fn":this.program(5, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                    ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.City : depth0), {"name":"if","hash":{},"fn":this.program(7, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n                    ";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Zip : depth0), {"name":"if","hash":{},"fn":this.program(9, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n                </p>\n";
},"3":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.Address1 : depth0), depth0))
    + ", ";
},"5":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.Address2 : depth0), depth0))
    + ", ";
},"7":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.City : depth0), depth0))
    + ", ";
},"9":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda((depth0 != null ? depth0.Zip : depth0), depth0))
    + " ";
},"11":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "        <div class=\"row\">\n            <div class=\"res-1600-cols-3 res-1024-cols-6\">\n                <p>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.scheduler : stack1)) != null ? stack1.label : stack1)) != null ? stack1.current2 : stack1), depth0))
    + "</p>\n            </div>\n            <div class=\"res-1600-cols-3 res-1024-cols-6\">\n                <div class=\"image\"></div>\n                <p class=\"dealer-option\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.scheduler : stack1)) != null ? stack1.label : stack1)) != null ? stack1.option : stack1), depth0))
    + "</p>\n                <p class=\"dealer-description\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.scheduler : stack1)) != null ? stack1.label : stack1)) != null ? stack1.description : stack1), depth0))
    + "</p>\n            </div>\n        </div>\n";
},"13":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.data : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Xtime : stack1)) != null ? stack1.Desktop : stack1), depth0));
  },"15":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.data : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Xtime : stack1)) != null ? stack1.Mobile : stack1), depth0));
  },"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "<div class=\"inner\">\n    <div class=\"container\">\n\n        <div class=\"row\">\n            <div class=\"res-1600-cols-12 res-1024-cols-12\">\n                <h1>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.scheduler : stack1)) != null ? stack1.label : stack1)) != null ? stack1.title : stack1), depth0))
    + "</h1>\n            </div>\n        </div>\n\n";
  stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 != null ? depth0.data : depth0)) != null ? stack1.Dealer : stack1), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.program(11, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n        <div class=\"row overlay-buttons\">\n            <a href=\"";
  stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.data : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Xtime : stack1)) != null ? stack1.Desktop : stack1), {"name":"if","hash":{},"fn":this.program(13, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\" target=\"_blank\" class=\"button button-icon external desktop\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.scheduler : stack1)) != null ? stack1.button : stack1)) != null ? stack1.action1 : stack1), depth0))
    + "</a>\n            <a href=\"";
  stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.data : depth0)) != null ? stack1.Dealer : stack1)) != null ? stack1.Xtime : stack1)) != null ? stack1.Mobile : stack1), {"name":"if","hash":{},"fn":this.program(15, data),"inverse":this.program(13, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\" target=\"_blank\" class=\"button button-icon external mobile\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.scheduler : stack1)) != null ? stack1.button : stack1)) != null ? stack1.action1 : stack1), depth0))
    + "</a>\n            <a href=\"#\" class=\"button button-icon\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.scheduler : stack1)) != null ? stack1.button : stack1)) != null ? stack1.action2 : stack1), depth0))
    + "</a>\n        </div>\n\n    </div>\n</div>";
},"useData":true});
this["templates"]["_tabs"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<ul class=\"tab-helper level-1\">\n    <li><a href=\"#\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.dealertabs : stack1)) != null ? stack1.label : stack1)) != null ? stack1.dealer : stack1), depth0))
    + "</a></li>\n    <li class=\"disabled\"><a href=\"#\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.dealertabs : stack1)) != null ? stack1.label : stack1)) != null ? stack1.location : stack1), depth0))
    + "</a></li>\n    <li><a href=\"#\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.dealertabs : stack1)) != null ? stack1.label : stack1)) != null ? stack1.postcode : stack1), depth0))
    + "</a></li>\n  \n</ul>\n\n<ul class=\"tab-helper level-2 search-content helper-form\">\n\n\n    <!-- START Search by dealer name -->\n    <li class=\"tab-item tab-dealer\">\n        <form action=\"\" method=\"POST\">\n            <fieldset class=\"dealerlocator-step\">\n            <div class=\"field-row\">\n                <div class=\"field\" data-validation=\"single\">\n\n                    <div class=\"subrow field-label\">\n                        <div class=\"res-1024-cols-12\">\n                            <label>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabdealer : stack1)) != null ? stack1.label : stack1)) != null ? stack1.title : stack1), depth0))
    + "</label>\n                        </div>\n                    </div>\n                    <div class=\"subrow\">\n                        <div class=\"res-1024-cols-5\">\n                            <div class=\"field-input dealer\">\n                                <div class=\"field-wrapper\">\n                                    <input type=\"text\" placeholder=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabdealer : stack1)) != null ? stack1.label : stack1)) != null ? stack1.placeholder : stack1), depth0))
    + "\" name=\"dealer\" value=\"\"\n                                           data-validation-id=\"dealer\"\n                                           data-validation-matchers=\"[Validation.matchers.isNotEmpty]\" />\n                                </div>\n                            </div>\n                            <button type=\"submit\" class=\"search\" title=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabdealer : stack1)) != null ? stack1.label : stack1)) != null ? stack1.title : stack1), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabdealer : stack1)) != null ? stack1.button : stack1), depth0))
    + "</button>\n                        </div>\n                        <div class=\"res-1024-cols-7 validation-container\">\n                            <div class=\"validation\" data-validation-message=\"dealer\" data-validation-match=\"0\">\n                                "
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabdealer : stack1)) != null ? stack1.validation : stack1)) != null ? stack1.required : stack1), depth0))
    + "\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            </fieldset>\n\n            <div class=\"container notify\"></div>\n            <div class=\"container results\"></div>\n        </form>\n    </li>\n    <!-- END Search by dealer name -->\n\n    <!-- START Search by location -->\n    <li class=\"tab-item tab-location\">\n        <form action=\"\">\n            <div class=\"container location\"></div>\n            <div class=\"container notify\"></div>\n            <div class=\"container results\"></div>\n        </form>\n    </li>\n    <!-- END Search by location -->\n\n    <!-- START Search by postcode -->\n    <li class=\"tab-item tab-postcode\">\n        <form action=\"\" method=\"POST\">\n            <fieldset class=\"dealerlocator-step\">\n            <div class=\"field-row\">\n                <div class=\"field\" data-validation=\"single\">\n                    <div class=\"subrow field-label\">\n                        <div class=\"res-1024-cols-12\">\n                            <label>"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabpostcode : stack1)) != null ? stack1.label : stack1)) != null ? stack1.title : stack1), depth0))
    + "</label>\n                        </div>\n                    </div>\n                    <div class=\"subrow\">\n                        <div class=\"region-error\">\n                            "
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.provinceerror : stack1), depth0))
    + "\n                            <p>\n                                <a href=\"#\" class=\"cta-btn dealer-refresh dealer-location disabled\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.location : stack1)) != null ? stack1.label : stack1)) != null ? stack1.button : stack1), depth0))
    + "</a>\n                            </p>   \n                        </div>\n                        <div class=\"res-1024-cols-5\">\n                          <div class=\"field-input postcode\">\n                                <input type=\"text\" name=\"postcode\" placeholder=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabpostcode : stack1)) != null ? stack1.label : stack1)) != null ? stack1.placeholder : stack1), depth0))
    + "\" value=\"\"\n                                       maxlength=\"6\"\n                                       data-validation-id=\"postcode\"\n                                       data-validation-matchers=\"[Validation.matchers.isNotEmpty, Matchers.isValidPostcode]\" />\n                            </div>\n                            <button type=\"submit\" class=\"search\" title=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabpostcode : stack1)) != null ? stack1.label : stack1)) != null ? stack1.title : stack1), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabpostcode : stack1)) != null ? stack1.button : stack1), depth0))
    + "</button>\n                        </div>\n                        <div class=\"res-1024-cols-7 validation-container\">\n                            <div class=\"validation\" data-validation-message=\"postcode\" data-validation-match=\"0\">\n                                "
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabpostcode : stack1)) != null ? stack1.validation : stack1)) != null ? stack1.required : stack1), depth0))
    + "\n                            </div>\n                            <div class=\"validation\" data-validation-message=\"postcode\" data-validation-match=\"1\">\n                                "
    + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.language : depth0)) != null ? stack1.dealerlocatorstep : stack1)) != null ? stack1.fields : stack1)) != null ? stack1.tabpostcode : stack1)) != null ? stack1.validation : stack1)) != null ? stack1.required : stack1), depth0))
    + "\n                            </div>                       \n                        </div>\n                    </div>\n                </div>\n            </div>\n            </fieldset>\n            <div class=\"container notify\"></div>\n            <div class=\"container results\"></div>\n        </form>\n\n    </li>\n    <!-- END Search by postcode -->\n\n</ul>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.dealer-locator.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("dealer-locator", function(application) {
// Handles getting current location OR interacts with location service
// Handles 3 search inputs: current location, post code, keyword
// Handles showing results = interacts with dealer locator API
// Handles pagination
// Interacts with map helper (which in turn interacts with Google Maps service)

// Is configurable
// Which dealer services to show
// Which order for dealer services
// Number of results to show per page
var $__Object$defineProperties = Object.defineProperties;
var $__Object$defineProperty = Object.defineProperty;

var DealerLocator = function() {
    "use strict";

    function DealerLocator(config) {
        this.Services = new app.services();
        this.Helpers = new app.helpers();
        this.Geocoder = (typeof google === "object" && typeof google.maps === "object") ? new google.maps.Geocoder() : null;
        this.regionSearch = false;
        this.regionPostcodeSearch = false;
        var defaultConfig = {
			scope: null,
			dealerService: false,
			order: null,
			limit: 3,
			language: null,
			services: {
				sales: true,
				service: true,
				parts: true
			},
			api: {
				// TODO: Backend needs to sort out tregionSearchheir ApiServices duplication issue.
				//location:'GetDealersByCoordinates',
				//postcode:'GetDealersByPostCode',
				//keywords:'SearchDealers',
				//dealer:'GetDealer'

				location: "/api/dealersearch/query/location",
				postcode: "/api/dealersearch/query/postcode",
				keywords: "/api/dealersearch/query/keywords",
				dealer: "/api/dealersearch/dealer",
				prefecture: "/api/dealersearch/query/prefecture"
			},
			province: {
				PROVINCE_DATA_ATTRIBUTE: "active-region",
    			ENABLE_PROVINCE: "enable-province",
   				LOCATION_FOUND: "location-found"
			},
			scheduler: false,
			onDealerSelected: function() {},
			refreshMap: function() {
                this.mapRefresh();
            }.bind(this)
		};

        this.config = $.extend({}, defaultConfig, config);

        this.serviceType = [];

        console.log(this.config);

        this.Templates = {
			_Tabs: this.Services.templateService.templates("helper.dealer-locator._tabs"),
			_Map: this.Services.templateService.templates("helper.dealer-locator._map"),
			_Results: this.Services.templateService.templates("helper.dealer-locator._results"),
			_Details: this.Services.templateService.templates("helper.dealer-locator._details"),
			_NoResults: this.Services.templateService.templates("helper.dealer-locator._noResults"),
			_Location: this.Services.templateService.templates("helper.dealer-locator._location"),
			_MapOverlay: this.Services.templateService.templates("helper.dealer-locator._mapOverlay"),
			_DealerBtn: this.Services.templateService.templates("helper.dealer-locator._dealerBtn"),
			_SchedulerOverlay: this.Services.templateService.templates("helper.dealer-locator._schedulerOverlay")
		};

        this.$currentTab = null;
        this.language = null;

        this.cultureCode = ($("body").data("culture-code")) ? $("body").data("culture-code").toLowerCase() : "en-gb";

        this.preferredDealerId = null;
        this.preferredDealer = [];
        this.dealerResults = [];

        this.map = [];
        this.locationEnabled = false;
        this.locationHasRun = false;
        this.position = null;

        setTimeout(function() {
            this.datetime = new (this.Helpers["date-time"]);
            this.pagetools = this.Services.pagetools;
            this.geolocation = this.Services.geolocation;
            this.sessions = this.Services.session;
            this.init();
        }.bind(this));
    }

    $__Object$defineProperties(DealerLocator.prototype, {
        init: {
            value: function() {
                var self = this;

                $.each(this.config.services, function(index, value) {
                    if(value){
                        self.serviceType.push(index);
                    }
                });

                this.language = this.config.language ? this.config.language : this.config.scope.data("language");
                this._window = this.pagetools.window._element[0];
                this.$body = this.pagetools.body._element;

                self.config.scope.addClass("dealer-locator-helper");
                // set date language
                self.datetime.moment().locale(this.cultureCode);

                if (this.detectIE()) {
                    self.config.scope.addClass("ie");
                }

                if (!this.language) {
                    console.log("The dealer locator module requires a language data-attribute to function.");
                    return false;
                }

                if(this.config.region && this.config.region.enableProvince == "True" && this.config.region.locationFound == "True" && this.config.region.activeRegion)
                    this.regionSearch = true;
                // create a promise to show by location if we can detect browser location.
                this.tabCreate();
                this.preferredDealerCheck();
                this.initResize();
            },

            enumerable: false,
            writable: true
        },

        initResize: {
            value: function() {
                var self = this,
                    resizeTimer;

                $(this._window).resize(function() {
                    if(resizeTimer) {
                        clearTimeout(resizeTimer);
                    }
                    resizeTimer = setTimeout(function()
                    {
                        // if we have a location, then lets
                        $.when(self.locationCheck()).then(function() {
                            self.locationShow();
                            self.config.refreshMap.call(this);
                        }, function() {
                            console.log("no location could be found");
                        });

                        resizeTimer = null;
                    }, 1000);
                });
            },

            enumerable: false,
            writable: true
        },

        mapRefresh: {
            value: function() {
                $.each(this.map, function(index, value) {
                    this.map.invalidateSize();
                    this.fitToMarkers();
                });
            },

            enumerable: false,
            writable: true
        },

        tabCreate: {
            value: function() {
                var self = this,
                    tabsTemplate = this.Templates._Tabs({language: this.language});

                this.config.scope.addClass("on").append(tabsTemplate);

                var defaultTabIndex;

                if(!!this.config.scope.data("maxmind")){
                    defaultTabIndex = 2;
                }else if(this.regionSearch){
                    defaultTabIndex = 1;
                }else{
                    defaultTabIndex = 0;
                }

                var tabConfig = {
                    tabSet: this.config.scope.find(".tab-helper.level-1"),
                    tabContentSet: this.config.scope.find(".tab-helper.level-2"),
                    defaultTabIndex: defaultTabIndex,
                    onTabClick: function onTabClick(index) {
                        if(!!self.config.scope.data("maxmind") && index === 1){
                            return;
                        }
                        self.tabClickEvent(index);
                    },
                    afterInit: function afterInit() {
                        if(!!self.config.scope.data("maxmind")){
                            self.config.scope.find(".dropdown-helper.level-2 li").eq(1).addClass("disabled");

                            self.$currentTab = self.config.scope.find(".tab-helper.level-2 .tab-item").eq(2);
                            self.postcodeInit();
                        }
                        else if(self.regionSearch){
                            self.$currentTab = self.config.scope.find(".tab-helper.level-2 .tab-item").eq(1);
                            self.locationInit();
                        }else {
                            self.$currentTab = self.config.scope.find(".tab-helper.level-2 .tab-item").eq(0);
                            //self.postcodeInit();
                            self.dealerInit();
                        }
                        self.globalBindEvents();
                    }
                };

                this.tab = new (this.Helpers.tabs)(tabConfig);

                if(!!self.config.scope.data("maxmind")){}else{
                    // if we have a location, then lets
                    $.when(this.locationCheck()).then(function() {
                        self.locationShow();
                    }, function() {
                        console.log("no location could be found");
                    });
                }
            },

            enumerable: false,
            writable: true
        },

        tabClickEvent: {
            value: function(index) {
                this.$currentTab = this.config.scope.find(".tab-helper.level-2 .tab-item").eq(index);

                switch(index) {
                    case 1:
                        // location
                        this.locationInit();
                        break;
                    case 2:
                        // postcode
                        this.postcodeInit();
                        break;
                    default:
                        // dealer name
                        this.dealerInit();
                }

                this.globalBindEvents();
            },

            enumerable: false,
            writable: true
        },

        preferredDealerCheck: {
            value: function() {
                var self = this;

                if(this.config.provinceService) {
                    this.getData({
                        url: this.config.provinceService,
                        params: {
                            serviceType: this.serviceType.toString()
                        }
                    });
                } else {
                    $.when(this.preferredDealerGet()).then(function (dealerId) {
                        if (dealerId) {
                            $.ajax({
                                dataType: "json",
                                url: self.config.api.dealer,
                                data: {
                                    dealerId: dealerId,
                                    shopId: dealerId,
                                    lang: self.$body.attr("data-lang"),
                                    serviceType: self.serviceType.toString()
                                }
                            }).done(function(data) {
                                var ServicesList = [];
                                $.each(data.Dealer.Services, function( index, value ) {
                                    ServicesList.push(value.Service);
                                });

                                if(ServicesList.length){
                                    if( ($.inArray("Sales", ServicesList) === -1) && (self.config.scope.closest(".helper-form").hasClass("module-test-drive")) ){
                                        self.preferredDealer = null;
                                    }else{
                                        self.preferredDealer = (data.Dealer.DealerId === dealerId ? data : null);
                                    }
                                }else{
                                    self.preferredDealer = (data.Dealer.DealerId === dealerId ? data : null);
                                }

                                if (self.preferredDealer) {
                                    self.schedulerCheck(data);
                                    self.config.onDealerSelected.call(this, data);
                                }
                            }.bind(this));
                        }
                    });
                }
            },

            enumerable: false,
            writable: true
        },

        preferredDealerSync: {
            value: function() {
                var self = this,
                    deferred = $.Deferred();

                $.when(this.preferredDealerGet()).then(function(dealer) {
                    if (dealer) {
                        self.config.scope.find("[data-id='" + dealer + "']").addClass("preferred");
                        self.config.scope.find(".dealer-preferred").empty().append(self.Templates._DealerBtn({language: self.language}));
                        self.config.scope.find("[data-id='" + dealer + "'] .dealer-preferred").empty().append(self.Templates._DealerBtn({active: true, language: self.language}));

                        deferred.resolve(dealer);
                    } else {
                        self.config.scope.find("[data-id]").removeClass("preferred");
                        self.config.scope.find(".dealer-preferred").empty().append(self.Templates._DealerBtn({language: self.language}));

                        deferred.reject();
                    }

                    // set map markers
                    $.each(self.map, function(index, value) {
                        if (!$.isEmptyObject(value)) {
                            var map = value,
                                markers = value.markers;

                            $.each(markers, function(index, value) {
                                if (value.options.identifier === self.preferredDealerId) {
                                    map.setMarkerIcon(value,"preferred_marker");
                                } else {
                                    map.setMarkerIcon(value,"marker");
                                }
                            });
                        }
                    });
                });

                return deferred.promise();
            },

            enumerable: false,
            writable: true
        },

        preferredDealerGetById: {
            value: function() {
                var result = this.dealerResults.map(function(i) {
                    return i.filter(function(o) {
                        return o.Dealer.DealerId == this.preferredDealerId;
                    }.bind(this));
                }.bind(this))[this.$currentTab.index()];

                return (result && result.length) ? result[0] : null;
            },

            enumerable: false,
            writable: true
        },

        preferredDealerGet: {
            value: function() {
                var self = this,
                    deferred = $.Deferred();

                this.sessions.get(function(data) {
                    var dealer = (data.Data && data.Data.preferreddealer) ? data.Data.preferreddealer : null;

                    self.preferredDealerId = dealer;
                    deferred.resolve(dealer);
                });

                return deferred.promise();
            },

            enumerable: false,
            writable: true
        },

        preferredDealerSet: {
            value: function(value) {
                var self = this,
                    deferred = $.Deferred();

                this.sessions.set("preferredDealer", value, function() {
                    // success
                    self.preferredDealerId = value;
                    deferred.resolve(value);

                    var dealer = self.preferredDealerGetById(self.preferredDealerId);
                    self.preferredDealer = dealer;

                    self.schedulerCheck(dealer);
                    self.config.onDealerSelected.call(this, dealer);
                }, function(error) {
                    // fail
                    self.preferredDealerId = "";
                    self.preferredDealer = [];
                    self.config.onDealerSelected.call(this, null);
                    deferred.reject(error);
                });

                return deferred.promise();
            },

            enumerable: false,
            writable: true
        },

        globalBindEvents: {
            value: function() {
                var self = this;

                // marker click events
                this.$currentTab.off("click", "header a.marker").on("click", "header a.marker", function(e) {
                    e.preventDefault();

                    var currentMap = self.map[self.$currentTab.index()],
                        index = (parseInt($(this).parents("article").index()) - 1),
                        latLng = currentMap.markers[index].getLatLng(),
                        zoom = currentMap.map.getZoom();

                    currentMap.map.setView(latLng, zoom);

                    return false;
                });

                // dealer on select
                this.$currentTab.off("click", ".dealer-preferred a, header a.title").on("click", ".dealer-preferred a, header a.title", function(e) {
                    e.preventDefault();

                    var $button = $(this),
                        $currentDealer = $button.parents("[data-id]"),
                        value = $currentDealer.attr("data-id");

                    if ($currentDealer.hasClass("preferred")) {
                        $.when(self.preferredDealerSet("")).then(function() {
                            self.config.scope.find("[data-id]").removeClass("preferred");
                            self.config.scope.find(".dealer-preferred").empty().append(self.Templates._DealerBtn({language: self.language}));

                            self.preferredDealerSync();
                        });
                    } else {
                        $.when(self.preferredDealerSet(value)).then(function() {
                            self.config.scope.find("[data-id]").removeClass("preferred");
                            self.config.scope.find("[data-id='" + value + "']").addClass("preferred");

                            self.preferredDealerSync();
                        });
                    }

                    return false;
                });

                // switch to postcode link
                this.$currentTab.off("click", "a[href=\"#tab-postcode\"]").on("click", "a[href=\"#tab-postcode\"]", function(e) {
                    e.preventDefault();
                    if(self.pagetools.window.isMobile()){
                        self.config.scope.find(".dropdown-helper.level-2 li").eq(1).find("a").trigger("click");
                        self.config.scope.trigger("click");
                    }else{
                        self.config.scope.find(".tab-helper.level-1 li a").eq(1).trigger("click");
                    }
                    return false;
                });
            },

            enumerable: false,
            writable: true
        },

        getData: {
            value: function(options, query) {
                try {
                    var self = this;

                    var showError = function() {
                        self.$currentTab.find(".results").empty();
                        self.$currentTab.find(".notify").empty().append(self.Templates._NoResults({language: self.language}));

                        return false;
                    };

                    $.ajax({
                        dataType: "json",
                        url: options.url,
                        data: options.params
                    }).done(function(data) {
                        // allow dummy data if set.
                        if (self.config.dummy && (typeof self.config.dummy === "object")) {
                            data = self.config.dummy;
                            console.log(data);
                        }

                        // do we have any results?
                        if (data.length > 0) {
                            self.dealerResults[this.$currentTab.index()] = data;
                            self.resultsPopulate(data, query);
                        } else {
                            showError();
                        }

                        return data;
                    }.bind(this)).fail(function(data) {
                        console.log("Dealer search request failed: " + data);
                        showError();
                    });
                } catch(e) {
                    throw new Error(e);
                }
            },

            enumerable: false,
            writable: true
        },

        schedulerCheck: {
            value: function(result) {
                var self = this;

                if ((result.Dealer.Xtime && result.Dealer.Xtime.IsActive === true) && self.config.scheduler === true) {
                    self.schedulerOverlay();
                    return true;
                }

                return false;
            },

            enumerable: false,
            writable: true
        },

        schedulerOverlay: {
            value: function() {
                var self = this,
                template = {
                    data: this.preferredDealer,
                    language: this.language
                };

                // inject template with language details.
                var html = this.Templates._SchedulerOverlay(template),
                    overlayConfig = {
                        moduleClass: "dealer-locator-helper scheduler",
                        afterInit: function(element) {
                            if (element) {
                                var $element = $(element);
                                $element.html(html);
                            }

                            this.schedulerBindEvents(element);
                        }.bind(this),
                        afterClose: function(element) {
                            $.when(self.preferredDealerSet("")).then(function() {
                                self.config.scope.find("[data-id]").removeClass("preferred");
                                self.config.scope.find(".dealer-preferred").empty().append(self.Templates._DealerBtn({language: self.language}));
                                self.preferredDealerSync();
                            });
                        }
                    };

                // Instantiate the overlay.
                this.overlayHelper = new (this.Helpers["overlay"])(overlayConfig);
            },

            enumerable: false,
            writable: true
        },

        schedulerBindEvents: {
            value: function(element) {
                var self = this,
                    $externalButton = element.find(".overlay-buttons a").first(),
                    $cancelButton = element.find(".overlay-buttons a").last(),
                    $closeButton = $cancelButton.parents(".overlay-helper").find(".close");

                // let this click through, but also close/remove the overlay manually.
                $externalButton.off("click").on("click", function(e) {
                    element.parents(".overlay-helper").remove();
                    self.$body.removeClass("disable-overflow");
                });

                // close overlay and remove the chosen dealer.
                $cancelButton.off("click").on("click", function(e) {
                    e.preventDefault();
                    $closeButton.trigger("click");
                });

                $closeButton.off("click.dealer").on("click.dealer", function(e) {
                    var $dealerStep = self.$body.find(".dealerlocator-step");
                    if (!$dealerStep.hasClass("in")) {
                        $dealerStep.find(".top-panel a").trigger("click");
                    }
                });
            },

            enumerable: false,
            writable: true
        },

        resultsPopulate: {
            value: function(data, query) {
                var $__0;
                var self = this;

                // Temporary pre-go-live fix
                var toFrench = self.datetime.language.toLowerCase() === "fr-ca",
                    map = {
                        "Sunday": "Dimanche",
                        "Monday": "Lundi",
                        "Tuesday": "Mardi",
                        "Wednesday": "Mercredi",
                        "Thursday": "Jeudi",
                        "Friday": "Vendredi",
                        "Saturday": "Samedi",
                        "Sales": "Ventes",
                        "Service": "Service",
                        "Parts": "Pièces",
                        "Closed": "Fermé"
                    };
                // Temporary pre-go-live fix

                // Clone object
                data = JSON.parse(JSON.stringify(data));

                // process raw api data first to clean front-end requirements.
                $.each(data, function(key, val) {
                    var ServicesList = [];
                    data[key].Dealer.Index = val.ResultMetaData ? val.ResultMetaData.split("|")[0] : null;
                    data[key].Dealer.hasDetail = (val.Dealer.OpeningTimes.length > 0 || val.Dealer.CTA || val.Dealer.Awards) ? true : false;
                    data[key].Dealer.Weekday = self.datetime.moment().format("dddd");


                    $.each(data[key].Dealer.Services, function( index, value ) {
                        ServicesList.push(value.Service);
                    });

                    if(ServicesList.length){
                        if($.inArray("Sales", ServicesList) != -1){
                            data[key].Dealer.hasSales = true;
                        }else{
                            data[key].Dealer.hasSales = false;
                        }
                    }else{
                        data[key].Dealer.hasSales = false;
                    }


                    $.each(data[key].Dealer.OpeningTimes, function() {
                        var openingTimes = this;
                        openingTimes.Today = false;

                        var filtered = $.grep(data[key].Dealer.Services, function(val, index) {
                            if (openingTimes.ServiceType === val.ServiceType) {
                                return val.Service;
                            }
                        });

                        openingTimes.Service = filtered[0].Service;

                        // Temporary pre-go-live fix
                        if (toFrench) openingTimes.Service = map[openingTimes.Service];
                        // Temporary pre-go-live fix

                        $(this.Days).each(function() {
                            var format = "LT",
                            open = self.datetime.moment().startOf("day").hour(this.OpenTime.split(":")[0]).minute(this.OpenTime.split(":")[1]),
                            closed = self.datetime.moment().startOf("day").hour(this.CloseTime.split(":")[0]).minute(this.CloseTime.split(":")[1]),
                            day = this.Key ? this.Key : this.Day;

                            // Temporary pre-go-live fix
                            if (toFrench) {
                                day = map[day];
                                this.Day = map[this.Day];
                            }
                            // Temporary pre-go-live fix

                            this.DayMatch = this.Day.toLowerCase() === data[key].Dealer.Weekday.toLowerCase();

                            if( typeof this.OpenTime === "string" && this.OpenTime.split(":").length <= 1){
                                // Temporary pre-go-live fix
                                if (toFrench) this.OpenTime = map[this.OpenTime];
                                // Temporary pre-go-live fix

                                this.FormattedOpenTime = this.OpenTime;
                                this.SingleOpenCloseTime = true;
                            }else{
                                if (toFrench) {
                                    this.FormattedOpenTime = this.OpenTime.replace(":", " h ").replace("00", "").replace(/^(0)/, "");
                                } else {
                                    //for en lang changes time format to am / pm
                                    this.FormattedOpenTime = open.format("h:mm a");
                                }
                            }

                            if( typeof this.CloseTime === "string" && this.CloseTime.split(":").length <= 1){
                                // Temporary pre-go-live fix
                                if (toFrench) this.CloseTime = map[this.CloseTime];
                                // Temporary pre-go-live fix

                                this.FormattedCloseTime = this.CloseTime;
                                this.SingleOpenCloseTime = true;
                            }else{
                                if (toFrench) {
                                    this.FormattedCloseTime = this.CloseTime.replace(":", " h ").replace("00", "").replace(/^(0)/, "");
                                } else {
                                    //for en lang changes time format to am / pm
                                    this.FormattedCloseTime = closed.format("h:mm a");
                                }
                            }

                            if (self.datetime.moment().format("dddd").toLowerCase() === day.toLowerCase()) {
                                openingTimes.Today = self.datetime.moment().isBetween(open, closed) ? this.FormattedOpenTime +" - "+ this.FormattedCloseTime : false;
                            }
                        });
                    });
                });

                var pagination = $.map(data, function(d) {
                    var item = d.ResultMetaData.split("|"),
                        page = {
                            item: parseInt(item[0]),
                            total: parseInt(item[1]),
                            perPage: parseInt(self.config.limit),
                            page: (parseInt(data.length) >= self.config.limit) ? Math.floor(parseInt(item[0]) / parseInt(data.length)) : 0,
                            pages: Math.floor(parseInt(item[1]) / parseInt(data.length)) - 1
                        };

                    return page;
                });

                var totalResults =  parseInt(data[0].ResultMetaData.split("|")[1]);
                var perPage = parseInt(self.config.limit);

                var paginationLogic = {
                    totalResults: totalResults,
                    perPage: perPage,
                    pagesTotal: Math.ceil(totalResults / perPage),
                    currentPage: Math.ceil(data[0].ResultMetaData.split("|")[0] / perPage)
                };

                var locator = (this.position) ? [this.position.coords.latitude, this.position.coords.longitude] : null,
                result = {
                    position: this.position,
                    query: query,
                    dealers: data,
                    language: self.language,
                    pagination: pagination,
                    services: self.config.services,
                    pg: paginationLogic
                };

                var resultsTemplate = this.Templates._Results(result);

                this.$currentTab.find(".notify").empty();
                this.$currentTab.find(".results").empty().append(resultsTemplate);

                if (this.$currentTab.hasClass("tab-location")) {
                    this.locationHasRun = true;
                }

                // look for the map and set attributes for leaflet helper
                var $map = this.$currentTab.find(".map-container");

                var markerArray = [];
                for(var i in result.dealers) {
                    var index = result.dealers[i].Dealer.Index,
                        obj = ($__0 = {}, $__Object$defineProperty($__0, index, {
                            value: [result.dealers[i].Dealer.Address[0].Latitude, result.dealers[i].Dealer.Address[0].Longitude],
                            enumerable: true,
                            configurable: true,
                            writable: true
                        }), $__Object$defineProperty($__0, "identifier", {
                            value: result.dealers[i].Dealer.DealerId,
                            enumerable: true,
                            configurable: true,
                            writable: true
                        }), $__Object$defineProperty($__0, "count", {
                            value: i,
                            enumerable: true,
                            configurable: true,
                            writable: true
                        }), $__0);

                    markerArray.push(obj);
                }

                // create map.
                this.map[this.$currentTab.index()] = new (this.Helpers["leaflet-map"])({
                    container: $map[0],
                    locator: locator,
                    markers: markerArray,
                    providers: ["GMR"],
                    streetview_active: true,
                    onMarkerClick: function onMarkerClick(marker,event) {
                        self.mapCreateOverlay(this,marker,event);
                    }
                });

                // create map binds
                this.mapBindEvents();

                // synchronise currently preferred dealers
                this.preferredDealerSync();

                // create detail container
                this.resultsCreateDetailAccordion();

                // create opening time accordion
                this.resultsCreateTimeAccordion();

                // disable Locator if location is NOT enabled and zoom to results.
                var $locator = this.$currentTab.find(".map-locator");

                if (this.locationEnabled) {
                    $locator.addClass("on");
                    setTimeout(function(){
                        this.map[this.$currentTab.index()].fitToMarkers();
                    }.bind(this),1000);
                } else {
                    $locator.removeClass("on");
                    this.map[this.$currentTab.index()].fitToMarkers();
                }

                // store map to DOM
                self.config.scope.data("dealer", this.map[this.$currentTab.index()]);
            },

            enumerable: false,
            writable: true
        },

        resultsCreateDetailAccordion: {
            value: function() {
                this.$currentTab.find("article").each(function(index)
                {
                    var $article = $(this);
                    $article.off("click", ".detail-thumb a").on("click", ".detail-thumb a", function(e) {
                        e.preventDefault();

                        $article.find(".detail-inner").toggleClass("active");
                        $(this).find(".cta-btn").removeClass("show");

                        if ( $article.find(".detail-inner").hasClass("active") ) {
                            $(this).find(".cta-btn.less").addClass("show");
                        } else {
                            $(this).find(".cta-btn.more").addClass("show");
                        }
                        return false;
                    });
                });
            },

            enumerable: false,
            writable: true
        },

        resultsCreateTimeAccordion: {
            value: function() {
                var self = this;

                this.$currentTab.find("article").each(function(index)
                {
                    if ($(this).find(".times-accordion li").length > 0)
                    {
                        var accord = new (self.Helpers.accordion)({
                            $container: $(this).find(".dealer-times"),
                            multi: false,
                            selectors: {
                                accordion: ".times-accordion",
                                accordionItem: ".times-inner",
                                accordionItemThumb: ".times-thumb a",
                                accordionItemContent: ".times-content"
                            },
                            selection: function($element,status) {
                                $element[status?"addClass":"removeClass"]("active");
                            }
                        });

                        accord.toggleByIndex(0);
                    }
                });
            },

            enumerable: false,
            writable: true
        },

        mapCreateOverlay: {
            value: function(mapper, marker, event) {
                var latLng = marker.getLatLng(),
                    zoom = mapper.map.getZoom();

                mapper.map.setView(latLng, zoom);

                if (this.$currentTab.find(".results").hasClass("off"))
                {
                    var self = this,
                        overlay = this.$currentTab.find(".map-overlay"),
                        index = parseInt(marker.options.count),
                        result = {
                            label: marker.options.icon.options.labelText,
                            dealers: self.dealerResults[this.$currentTab.index()][index],
                            language: self.language,
                            services: self.config.services
                        },
                        overlayTemplate = this.Templates._MapOverlay(result);

                    overlay.empty().append(overlayTemplate).addClass("active");
                    self.preferredDealerSync();

                    // bind close
                    overlay.off("click", ".close").on("click", ".close", function() {
                        overlay.removeClass("active");
                    });

                    // bind body
                    $("body").off("click").on("click", function(e)
                    {
                        // if true then close the tab and remove event.
                        if ($(e.target).closest(overlay).length === 0) {
                            overlay.removeClass("active");
                        }
                    });
                }
            },

            enumerable: false,
            writable: true
        },

        mapBindEvents: {
            value: function() {
                var self = this,
                    map = this.map[this.$currentTab.index()],
                    $resultsContainer = this.$currentTab.find(".results");

                // Full screen
                $resultsContainer.find(".fullsize-control-toggle button").on("click", function() {
                    $resultsContainer.toggleClass("off");
                });
            },

            enumerable: false,
            writable: true
        },

        locationInit: {
            value: function() {
                var self = this;

                this.locationBindEvents();

                if (this.regionSearch === true){
                    var locationTemplate = self.Templates._Location({position: "", language: self.language});
                    self.$currentTab.find(".location").empty().append(locationTemplate);
                    self.$currentTab.find(".location .region-reset .region-name").text(this.config.region.activeRegion);
                    self.$currentTab.find(".location .region-reset").show();
                    this.locationData(0);
                } else if (this.locationEnabled === true) {
                    if (this.locationHasRun === false) {
                        this.locationData(0);
                    }

                    // check for their reverse lookup address and append details to the page.
                    $.when(this.locationReverseLookup(this.position.coords.latitude, this.position.coords.longitude)).then(
                        function(position) {
                            var positionResult = position[0];

                            // Remove first component
                            var address = positionResult.formatted_address.split(", ");
                            address.shift();
                            address = address.join(", ");
                            positionResult.formatted_address = address;

                            var results = {
                                position: positionResult,
                                language: self.language
                            };

                            var locationTemplate = self.Templates._Location(results);
                            self.$currentTab.find(".location").empty().append(locationTemplate);
                        }
                    );
                } else {
                    this.locationCheck();
                }
            },

            enumerable: false,
            writable: true
        },

        locationBindEvents: {
            value: function() {
                var self = this;

                // prevent map buttons from submitting the form.
                this.$currentTab.find("form").off("submit").on("submit", function(e) {
                    e.preventDefault();

                    // remove keyboard from mobile devices on submit.
                    $(this).find("input").blur();

                    return false;
                });

                this.$currentTab.off("click", ".cta-btn.dealer-location").on("click", ".cta-btn.dealer-location", function(e) {
                    e.preventDefault();
                    if(self.config.region.retestLink)
                        self._window.open(self.config.region.retestLink,"_self");
                });

                // keep an eye on location and allow user to refresh their position
                this.$currentTab.off("click", "a.dealer-refresh").on("click", "a.dealer-refresh", function(e) {
                    e.preventDefault();

                    self.locationHasRun = false;
                    self.locationInit();

                    return false;
                });

                // pagination
                this.$currentTab.off("click", ".pagination a").on("click", ".pagination a", function(e) {
                    e.preventDefault();

                    var $button = $(this),
                        targetPage = $button.attr("data-target");

                    self.locationData(targetPage);
                    return false;
                });
            },

            enumerable: false,
            writable: true
        },

        locationData: {
            value: function(page) {
                var self = this;

                if (this.regionSearch === true){
                    this.position = null;
                    this.getData({
                        params: {
                            prefecture: self.config.region.activeRegion,
                            page: page ? page : 0,
                            limit: self.config.limit,
                            lang: self.$body.attr("data-lang"),
                            serviceType: self.serviceType.toString()
                        },
                        url: self.config.api.prefecture
                    });
                }else if (this.locationEnabled === true) {
                    var latitude = this.position.coords.latitude,
                        longitude = this.position.coords.longitude;

                    this.getData({
                        params: {
                            latitude: latitude,
                            longitude: longitude,
                            page: page ? page : 0,
                            limit: self.config.limit,
                            lang: self.$body.attr("data-lang"),
                            serviceType: self.serviceType.toString()
                        },
                        url: self.config.api.location
                    });
                }
            },

            enumerable: false,
            writable: true
        },

        locationCheck: {
            value: function() {
                var self = this,
                    check = "";

                if(this.config.region && this.config.region.enableProvince == "True" && this.config.region.locationFound == "True" && this.config.region.activeRegion){
                    console.log("provence set and found");
                    this.regionSearch = true;
                    self.locationEnabled = true;
                    self.locationHasRun = true;
                    self.config.scope.find(".tab-helper.level-1").find("li").first().next().removeClass("disabled");
                    return true;
                }else if(this.config.region && this.config.region.enableProvince == "True" && this.config.region.locationFound != "True"){
                    console.log("provence set not found");
                    this.regionPostcodeSearch = true;
                    this.config.scope.find(".region-error").show();
                    // https://jira.syzygy.co.uk/browse/SLAMCI-164
                    // } else if (this.detectIE() && !!this.config.scope.data('maxmind')) {
                    //    this.position = {
                    //        coords: this.config.scope.data('maxmind')
                    //    };
                    //    this.locationEnabled = true;
                    //    this.config.scope.find('.tab-helper.level-1').find('li').first().next().removeClass('disabled');
                    //    return position;
                    return false;
                } 
                 else if(!!this.config.scope.data("maxmind")){
                    this.locationEnabled = false;
                    this.config.scope.find(".tab-helper.level-1").find("li").first().next().addClass("disabled");
                    return false;
                }
                 else {
                    // if we have a location, then lets
                    console.log("nothing set");
                    check = $.when(self.geolocation.getPosition()).then(
                        function(position) {
                            if (position.coords.latitude) {
                                self.position = position;
                                self.locationEnabled = true;
                                self.config.scope.find(".tab-helper.level-1").find("li").first().next().removeClass("disabled");

                                return position;
                            }

                            return false;
                        },
                        function(status) {
                            self.position = null;
                            self.locationEnabled = false;
                            self.config.scope.find(".tab-helper.level-1").find("li").first().next().addClass("disabled");
                            return status;
                        }
                    );

                    return check;
                }
            },

            enumerable: false,
            writable: true
        },

        locationShow: {
            value: function() {
                var self = this,
                    $tabItems = self.config.scope.find(".tab-helper.level-1").find("li"),
                    $dropdownItems = self.config.scope.find(".tab-is-dropdown .dropdown-helper.level-2").find("li");

                if (self.locationEnabled === true) {
                    $tabItems.removeClass("disabled");
                    $tabItems.first().next().find("a").trigger("click");
                    $dropdownItems.first().next().find("a").trigger("click");

                    self.config.scope.find(".tab-is-dropdown .dropdown-helper.level-1").removeClass("selected");
                    self.config.scope.find(".tab-is-dropdown .dropdown-helper.level-2").removeClass("open");
                }
            },

            enumerable: false,
            writable: true
        },

        locationReverseLookup: {
            value: function(latitude, longitude) {
                var deferred = $.Deferred();

                if (this.Geocoder) {
                    // success
                    this.Geocoder.geocode({ "latLng": new google.maps.LatLng(latitude,longitude) }, deferred.resolve);
                } else {
                    //fail
                    deferred.reject();
                }

                return deferred.promise();
            },

            enumerable: false,
            writable: true
        },

        dealerInit: {
            value: function() {
                this.dealerBindEvents();
            },

            enumerable: false,
            writable: true
        },

        dealerBindEvents: {
            value: function() {
                var self = this;

                this.$currentTab.find("form").off("submit").on("submit", function(e) {
                    e.preventDefault();

                    // remove keyboard from mobile devices on submit.
                    $(this).find("input").blur();

                    var value = $(this).parents(".tab-dealer").find("input").val(),
                        validation = self.Helpers["form-manager"].Validation.fromTemplate($(this));

                    // call data on success, else false.
                    if (validation.result === true) {
                        self.$currentTab.find(".hasError").removeClass("hasError");
                        self.dealerData.call(self,0,value);
                    } else {
                        self.$currentTab.find(".field-input").addClass("hasError");
                    }

                    return false;
                });

                // pagination
                this.$currentTab.off("click", ".pagination a").on("click", ".pagination a", function(e) {
                    e.preventDefault();

                    var $button = $(this),
                        value = $(this).parents(".tab-dealer").find("input").val(),
                        targetPage = $button.attr("data-target");

                    self.dealerData(targetPage, value);
                    return false;
                });
            },

            enumerable: false,
            writable: true
        },

        dealerData: {
            value: function(page, value) {
                var self = this;

                this.getData({
                    params: {
                        searchTerm: value,
                        page: page ? page : 0,
                        limit: self.config.limit,
                        lang: self.$body.attr("data-lang"),
                        serviceType: self.serviceType.toString()
                    },
                    url: self.config.api.keywords
                }, value);
            },

            enumerable: false,
            writable: true
        },

        postcodeInit: {
            value: function() {
                this.postcodeBindEvents();
            },

            enumerable: false,
            writable: true
        },

        postcodeBindEvents: {
            value: function() {
                var self = this;

                this.$currentTab.find("form").off("submit").on("submit", function(e) {
                    e.preventDefault();

                    // remove keyboard from mobile devices on submit.
                    $(this).find("input").blur();

                    //var value = $(this).parents('.tab-postcode').find('input[name="postcode-one"]').val() + $(this).parents('.tab-postcode').find('input[name="postcode-two"]').val(),
                    var value = $(this).parents(".tab-postcode").find("input[name=\"postcode\"]").val(),
                        validation = self.Helpers["form-manager"].Validation.fromTemplate($(this), {
                            isValidPostcodePartOne: function (val) {
                                var regex = /^([a-zA-Z])([0-9])([a-zA-Z])/;
                                return regex.test(val);
                            },
                            isValidPostcodePartTwo: function (val) {
                                var regex = /^([0-9])([a-zA-Z])([0-9])/;
                                return regex.test(val);
                            },
                            isValidPostcode: function (val){
                                var regex = /^([a-zA-Z])([0-9])([a-zA-Z])([0-9])([a-zA-Z])([0-9])/;
                                return regex.test(val);
                            }
                        });

                    // call data on success, else false.
                    if (validation.result === true) {
                        self.$currentTab.find(".hasError").removeClass("hasError");
                        self.postcodeData.call(self, 0, value);
                    } else {
                        self.$currentTab.find(".field-input").addClass("hasError");
                    }

                    return false;
                });

                // detect input value length
                this.$currentTab.find("input").off("keyup").on("keyup", function() {
                    if ($(this).val().length >= 3) {
                        var inputs = self.$currentTab.find("input");
                        inputs.eq(($(this).index()+1)).focus();
                    }
                });

                this.$currentTab.find(".cta-btn.dealer-location").off("click").on("click", function(e) {
                    e.preventDefault();
                    self._window.location.reload();
                });

                // pagination
                this.$currentTab.off("click", ".pagination a").on("click", ".pagination a", function(e) {
                    e.preventDefault();

                    var $button = $(this),
                    value = $(this).parents(".tab-postcode").find("input[name=\"postcode\"]").val(),
                    targetPage = $button.attr("data-target");

                    self.postcodeData(targetPage, value);
                    return false;
                });
            },

            enumerable: false,
            writable: true
        },

        postcodeData: {
            value: function(page, value) {
                var self = this,
                    params = {
                        postcode: value,
                        page: page ? page : 0,
                        limit: self.config.limit,
                        lang: self.$body.attr("data-lang"),
                        serviceType: self.serviceType.toString()
                    };

                if(this.regionPostcodeSearch){
                    params.region = this.config.region.activeRegion;
                }

                this.getData({
                    params: params,
                    url: self.config.api.postcode
                }, value);
            },

            enumerable: false,
            writable: true
        },

        detectIE: {
            value: function() {
                var ua = window.navigator.userAgent;

                var msie = ua.indexOf("MSIE ");
                if (msie > 0) {
                    // IE 10 or older => return version number
                    return parseInt(ua.substring(msie + 5, ua.indexOf(".", msie)), 10);
                }

                var trident = ua.indexOf("Trident/");
                if (trident > 0) {
                    // IE 11 => return version number
                    var rv = ua.indexOf("rv:");
                    return parseInt(ua.substring(rv + 3, ua.indexOf(".", rv)), 10);
                }

                var edge = ua.indexOf("Edge/");
                if (edge > 0) {
                    // IE 12 => return version number
                    return parseInt(ua.substring(edge + 5, ua.indexOf(".", edge)), 10);
                }

                // other browser
                return false;
            },

            enumerable: false,
            writable: true
        }
    });

    return DealerLocator;
}();

return DealerLocator;
});
}).apply(window);/**!!<[helper.dealer-locator]!!**/
/**!![helper.drop-down]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_dropdowns"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "        <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "><a href=\""
    + escapeExpression(((helper = (helper = helpers.url || (depth0 != null ? depth0.url : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"url","hash":{},"data":data}) : helper)))
    + "\" title=\""
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "\">";
  stack1 = ((helper = (helper = helpers.content || (depth0 != null ? depth0.content : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"content","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</a></li>\n";
},"2":function(depth0,helpers,partials,data) {
  return "class=\"selected\"";
  },"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, lambda=this.lambda, buffer = "<div class=\"dropdown-wrapper\">\n    <div class=\"dropdown-helper level-1 "
    + escapeExpression(((helper = (helper = helpers.dropdownState || (depth0 != null ? depth0.dropdownState : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"dropdownState","hash":{},"data":data}) : helper)))
    + "\">\n        <a href=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.items : depth0)) != null ? stack1['0'] : stack1)) != null ? stack1.url : stack1), depth0))
    + "\" title=\""
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.items : depth0)) != null ? stack1['0'] : stack1)) != null ? stack1.title : stack1), depth0))
    + "\">";
  stack1 = ((helper = (helper = helpers.label || (depth0 != null ? depth0.label : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"label","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  buffer += "</a>\n    </div>\n    <ul class=\"dropdown-helper level-2\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "    </ul>\n</div>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.drop-down.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("drop-down", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var DropDown = function() {
    "use strict";

    function DropDown(config) {
        var Services = new app.services();

        var defaultConfig = {
            scope: null,
            preventDefault: true,
            listType: "li",
            level1: ".dropdown-helper.level-1",
            level2: ".dropdown-helper.level-2",
            template: "helper.drop-down._dropdowns",
			scrollable: false,
            disabled: false,
            label: null,
            insertion: "append",
			defaultDropownIndex: 0
        };

        this.config = $.extend({}, defaultConfig, config);

        this.Templates = {
            _dropdowns: Services.templateService.templates( this.config.template )
        };

        this.init();

        if (this.config.afterInit) {
            this.config.afterInit.apply();
        }
    }

    $__Object$defineProperties(DropDown.prototype, {
        init: {
            value: function() {
                var $scope;

                if (this.config.scope) {
                    $scope = $(this.config.scope);

                    // render template
                    if (this.config.collection)
                    {
                        var label = this.config.label || this.config.collection[0].content,
                            html = this.Templates._dropdowns({
                                items: this.config.collection,
                                label: label
                            });

                        $scope[this.config.insertion](html);

                        this.$level1 = $scope.find(this.config.level1);
                        // set directly from the dom
                        this.$level2 = $scope.find(this.config.level2);
                    } else {
                        this.$level1 = $scope.find(this.config.level1);
                        this.$level2 = $scope.find(this.config.level2);

                        // set optional label
                        if (this.config.label) {
                            this.$level1.find("a").text(this.config.label).removeAttr("title");
                        } else {
                            this.config.label = this.$level1.find("a").text();
                        }
                    }

                    // grab list set for optional manipulation.
                    this.$level2List = this.$level2.children(this.config.listType);

                    // set scroller and height limit if enabled in config.
                    if (this.config.scrollable !== false) {
                        var rem = this.pxToRem(this.config.scrollable);
                        this.$level2.attr("style", "max-height:"+parseInt(this.config.scrollable)+"px; max-height:"+rem+"rem;");
                        this.$level2.addClass("scrollable");
                    }

                    // if a collection exists and is empty, or the disabled config equals true, then disable button.
                    if ((this.config.collection && this.config.collection.length === 0) || this.config.disabled === true) {
                        this.setButtonState(false);
                    }

                    // Add helper class
                    $scope.addClass("dropdown-ready");
                } else {
                    console.log("Nothing to do!");
                    return;
                }

                this.bindEvents();
                this.defaultDropdown();
            },

            enumerable: false,
            writable: true
        },

        bindEvents: {
            value: function() {
                // reset all events
                this.$level1.find("a").off();
                this.$level2List.find("a").off();

                // click events for select
                this.$level1.on("click", "a", function(e) {
                    e.preventDefault();
                    var $dropdown = $(e.currentTarget).parent(),
                        $dropdownContent = $dropdown.next();

                    this.toggleDropdown($dropdown, $dropdownContent);

                    // extendable hook for select click
                    if (this.config.selectClick) {
                        this.config.selectClick.apply(this, [e.currentTarget, $dropdown, $dropdownContent]);
                    }
                }.bind(this));

                // click events for options
                this.$level2.on("click", "a", function(e) {
                    if($(e.target).closest("li").hasClass("disabled")){
                        e.preventDefault();
                        return;
                    }

                    // optional trigger to prevent link action on click.
                    if (this.config.preventDefault === true) {
                        e.preventDefault();
                    }

                    var $target = $(e.currentTarget),
                        $dropdown = $target.parents( this.config.level2 ).prev(),
                        $dropdownContent = $target.parents( this.config.level2 );

                    // set selected
                    this.setItemState($target.parent(this.config.listType));

                    // set select text
                    $dropdown.find("a").replaceWith($target.clone());

                    this.toggleDropdown($dropdown, $dropdownContent);

                    // extendable hook for option click
                    if (this.config.optionClick) {
                        this.config.optionClick.apply(this, [$(e.currentTarget), $dropdown, $dropdownContent]);
                    }
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        bindBodyClick: {
            value: function() {
                var self = this;

                $("body").on("click.dropdownHelper touchend.dropdownHelper", function(e) {
                    // if true then close the tab and remove event.
                    if ($(e.target).closest(self.$level1).length === 0 && $(e.target).closest(self.$level2).length === 0) {
                        $(self.$level1).removeClass("selected");
                        $(self.$level2).removeClass("open");
                        self.unbindBodyClick();
                    }
                });
            },

            enumerable: false,
            writable: true
        },

        unbindBodyClick: {
            value: function() {
                $("body").off("click.dropdownHelper touchend.dropdownHelper");
            },

            enumerable: false,
            writable: true
        },

        toggleDropdown: {
            value: function($dropdown, $dropdownContent) {
                // close all instances of open dropdowns first (apart from the one we clicked on).
                $(".dropdown-ready").find(".level-1").not($dropdown).removeClass("selected");
                $(".dropdown-ready").find(".level-2").not($dropdownContent).removeClass("open");

                // the toggle .selected from the currently selected item
                $dropdown.toggleClass("selected");
                $dropdownContent.toggleClass("open");

                if ($dropdown.hasClass("selected")) {
                    this.bindBodyClick();
                } else {
                    this.unbindBodyClick();
                }
            },

            enumerable: false,
            writable: true
        },

        setItemState: {
            value: function($target) {
                this.$level2List.removeClass("selected");
                $target.addClass("selected");
            },

            enumerable: false,
            writable: true
        },

        setButtonState: {
            value: function(bool) {
                if (bool === false) {
                    this.$level1.addClass("disabled");
                } else {
                    this.$level1.removeClass("disabled");
                }

                return bool;
            },

            enumerable: false,
            writable: true
        },

        pxToRem: {
            value: function(pixels) {
                // decimal places
                var accuracy = 4;
                var base = 16;

                var rem = parseFloat( ( parseInt(pixels) / parseInt(base, 10) ).toPrecision(accuracy) );
                return rem;
            },

            enumerable: false,
            writable: true
        },

        defaultDropdown: {
            value: function() {
                var $level2Item = $(this.$level2List.get(this.config.defaultDropownIndex));

                if (this.config.defaultDropownIndex > 0) {
                    this.setItemState($level2Item);

                    // set select text
                    this.$level1.find("a").replaceWith($level2Item.find("a").clone());
                }
            },

            enumerable: false,
            writable: true
        },

        resetDefault: {
            value: function() {
                this.$level2List.removeClass("selected");

                var defaultOption = this.$level1.find("a");

                defaultOption.text(this.config.label);
                defaultOption.removeAttr("title");
                defaultOption.val("");
                defaultOption.attr("href", "#");
            },

            enumerable: false,
            writable: true
        }
    });

    return DropDown;
}();

return DropDown;
});
}).apply(window);/**!!<[helper.drop-down]!!**/
/**!![helper.form-manager]>!!**/
(function(){
registerHelper("form-manager", function(application) {
var FormManager = (function () {
  var createStep = function (step) {
    step = step instanceof FormStep ? step : new FormStep(step);
    step.form = this;
    return step;
  };

  var getSteps = function (steps) {
    return steps.map(function (step) {
      return createStep.call(this, step);
    }.bind(this));
  };

  var getConfig = function (config) {
    return $.extend(true, {
      steps: [],
      currentStep: 0,
      data: {}
    }, config);
  };

  var FormManager = function (formConfig) {
    $.extend(this, getConfig(formConfig));
    this.steps = getSteps.call(this, this.steps);
    this.load(this.currentStep);
  };

  FormManager.prototype.addStep = function (step, place) {
    step = createStep.call(this, step);
    this.steps.push(step);
    this.moveStep(step, place);
    return this;
  };

  FormManager.prototype.removeStep = function (step) {
    step = isNaN(step) ? this.steps.indexOf(step) : step;
    if (!~step || step >= this.steps.length) return false;
    this.steps.splice(step, 1);
    return this;
  };

  FormManager.prototype.moveStep = function (step, newPlace) {
    step = isNaN(step) ? this.steps.indexOf(step) : step;
    if (isNaN(Math.max(step, newPlace)) || !~Math.min(step, newPlace) || Math.max(step, newPlace) >= this.steps.length) return false;
    step = this.steps[step];
    this.steps.splice(this.steps.indexOf(step), 1);
    this.steps.splice(newPlace, 0, step);
    return this;
  };

  FormManager.prototype.clear = function (steps) {
    steps = arguments.length == 0 ? (function (form) {
      form.data = {};
      return form.steps;
    })(this)
      : Array.prototype.slice.call(arguments, 0);
    steps.forEach(function (step) {
      step = isNaN(step) ? this.steps.indexOf(step) : step;
      if (!~step || step >= this.steps.length) return false;
      step = this.steps[step];
      step.clear();
    }.bind(this));
    return this;
  };

  FormManager.prototype.load = function (step, check, success) {
    step = isNaN(step) ? this.steps.indexOf(step) : step;
    if (!~step || step >= this.steps.length) return false;
    step = this.steps[step];
    step.loader.load((arguments.length >= 3 ? arguments[1] : undefined), (arguments.length >= 3 ? arguments[2] : arguments[1]));
    return this;
  };

  FormManager.prototype.isCurrentStep = function (step) {
    step = isNaN(step) ? this.steps.indexOf(step) : step;
    if (!~step || step >= this.steps.length) return false;
    return this.steps[step].isCurrentStep();
  };

  FormManager.prototype.nothingLoaded = function () {
    return !(this.currentStep instanceof FormStep);
  };

  return FormManager;
})();
var FormStep = (function () {
  var StepLoader = (function () {
    var bindStepEvents = function (step) {
      if (!step.container) return false;
      $(step.container).find("[go-to]").off("click").on("click", function (e) {
        e.preventDefault();
        step.form.steps[$(this).attr("go-to")].loader.load();
      });
      $(step.container).find("a[go-to-url]").attr("href", function (i, val) {
        if (!step.form.steps[$(this).attr("go-to-url")]) return false;
        return step.form.steps[$(this).attr("go-to-url")].url || val;
      });
    };

    var getStepLoader = function (check, onsuccess) {
      var loader = this;
      return loader.check(
        (check || loader.loading.check).bind(loader.step)
      ).success(function () {
        (onsuccess || loader.loading.onsuccess).apply(loader.step, Array.prototype.slice.call(arguments, 0));
        bindStepEvents(loader.step);
        console.log("current step", loader.step);
        loader.step.form.currentStep = loader.step;
      }).failed(loader.loading.onfailed.bind(loader.step));
    };

    var StepLoader = function (step, loading) {
      this.loading = $.extend(true, {
        check: function (resolve, reject) {
          resolve(step.data);
        },
        onresolve: function (success) {
          return success.apply(this, Array.prototype.slice.call(arguments, 1));
        },
        onreject: function (failed) {
          return failed.apply(this, Array.prototype.slice.call(arguments, 1));
        },
        onsuccess: function () {},
        onfailed: function () {}
      }, loading);
      this.step = step;
    };

    StepLoader.prototype.check = function (check, onresolve, onreject) {
      return new Resolver(
        (check || this.loading.check).bind(this.step) //check
        , (onresolve || this.loading.onresolve).bind(this.step) //success
        , (onreject || this.loading.onreject).bind(this.step) //failed
      );
    };

    StepLoader.prototype.load = function (check, onsuccess) {
      return getStepLoader.call(this, (arguments.length >= 2 ? arguments[0] : this.loading.check), (arguments.length == 2 ? arguments[1] : arguments[0]));
    };

    return StepLoader;
  })();

  var getStepFieldsLoading = function (step,loading) {
    return $.extend(true,{
      check: function (resolve, reject) {
        var _missing = step.fields.filter(function (item) {
          return step.form.data[item] == undefined && (!isNaN(step.form.currentStep) || isNaN(step.form.currentStep) && step.form.currentStep.data[item] == undefined);
        });
        if (_missing.length) return reject(_missing);
        return resolve(step.data);
      }
    },loading);
  }

  var createStepLoader = function (loading) {
    return loading instanceof StepLoader ? loading : new StepLoader(this, getStepFieldsLoading(this,loading));
  };

  var getConfig = function (config) {
    return $.extend(true, {
      id: config.id,
      container: undefined,
      fields: [],
      data: {},
      loader: createStepLoader.call(this, config.loading)
    }, config);
  };

  FormStep = function (stepConfig) {
    $.extend(this, getConfig.call(this, stepConfig));
  };

  FormStep.prototype.clear = function () {
    this.data = {};
    return this;
  };

  FormStep.prototype.isCurrentStep = function () {
    return this.form.currentStep === this;
  };

  return FormStep;
})();
var Resolver = (function () {
  var _resolve = function () {
    var _args = Array.prototype.slice.call(arguments, 0);
    _args.unshift(_success.bind(this));
    this.succeding.apply(this, _args);
  };

  var _reject = function () {
    var _args = Array.prototype.slice.call(arguments, 0);
    _args.unshift(_failed.bind(this));
    this.failing.apply(this, _args);
  };

  var _success = function () {
    this.isSuccess = Array.prototype.slice.call(arguments, 0);
    this.success(this.onsuccess);
  };

  var _failed = function () {
    this.isFailed = Array.prototype.slice.call(arguments, 0);
    this.success(this.onfailed);
  };

  var Resolver = function (check, succeding, failing) {
    this.succeding = succeding || function (success) {
      success.apply(this, Array.prototype.slice.call(arguments, 1));
    }.bind(this);
    this.failing = failing || function (failed) {
      failed.apply(this, Array.prototype.slice.call(arguments, 1));
    }.bind(this);
    this.isSuccess = undefined;
    this.isFailed = undefined;
    check(_resolve.bind(this), _reject.bind(this));
  };

  Resolver.prototype.success = function (callback) {
    this.onsuccess = callback;
    if (this.isSuccess && this.onsuccess) this.onsuccess.apply(this, this.isSuccess);
    return this;
  };

  Resolver.prototype.failed = function (callback) {
    this.onfailed = callback;
    if (this.isFailed && this.onfailed) this.onfailed.apply(this, this.isFailed);
    return this;
  };

  return Resolver;
})();
var Validation = (function () {
  var Success = (function() {
    var Success = function (validation, callback) {
      this.validation = validation;
      this.result = this.validation.result;
      this.failures = this.validation.failures.slice(0);
      this.values = $.extend({},this.validation.values);
      this.validation.failures = [];
      this.validation.values = {};

      switch (typeof callback) {
        case "function":
          break;
        default:
          callback = function () {
            return console.log("success", callback);
          };
          break;
      }
      if (this.result)callback.call(this.validation,this.values);
    };

    Success.prototype.failed = function (callback) {
      switch (typeof callback) {
        case "function":
          break;
        default:
          callback = function () {
            return console.log("failed", callback);
          };
          break;
      }
      if (!this.result)callback.call(this.validation, this.failures, this.values);
    };

    return Success;
  })();


  var Condition = (function(){
    var Condition = function (match, value, $field, id) {
      this.match = String(match);
      this.value = value;
      this.$field = $field;
      this.id = id;

      switch (typeof match) {
        case "function":
          this.result = match(this.value,this.$field);
          break;
        case "boolean":
          this.result = match;
          break;
        case "object":
          if (match instanceof RegExp) {
            this.result = match.test(this.value);
            break;
          }
        default:
          this.result = match === this.value;
          break;
      }
    };
    return Condition;
  })();

  var Check = (function(){
    var Check = function (condition, failure) {
      this.condition = condition;
      this.failure = failure;
    };

    Check.prototype.test = function(){
      if (!this.condition.result) this.failure.call(this,this.condition);
      return this.condition.result;
    };

    return Check;
  })();

  var addValue = function(values,condition){
    if (condition.id) values[condition.id] = condition.value;
  }

  var enqueueCheck = function(check){
    addValue(this.values,check.condition);
    if (this.type!=="single" || (this.type==="single" && this.result)){
      var result = check.test();
      this.result = this.result ? result : this.result;
    }
  };

  var setFailure = function (failure) {
    return function (condition) {
      if (typeof failure == "function") {
        return this.failures.push(failure(condition)||condition);
      }
      console.log(failure,condition);
    }.bind(this);
  };

  var Validation = function (type, failure) {
    this.type = type || "single";
    this.failure = setFailure.call(this,failure || function(condition){});
    this.result=true;
    this.values = {};
    this.failures = [];
  };

  Validation.prototype.check = function () {
    var _args = Array.prototype.slice.call(arguments, 0), check, condition, failure;

    switch (_args.length) {
      case 1:
        if (typeof _args[0] === "object"  && !(_args[0] instanceof RegExp)){
          condition =  new Condition(_args[0].match,_args[0].value,_args[0].$field,_args[0].id);
          failure = _args[0].failure ? setFailure.call(this,_args[0].failure) : this.failure;
        } else {
          condition =  new Condition(_args[0]);
          failure = this.failure;
        }
        break;
      case 2:
        condition = new Condition(_args[1], _args[0]);
        failure = this.failure;
        break;
      case 3:
        condition = new Condition(_args[1], _args[0]);
        failure = setFailure.call(this,_args[2])
        break;
      case 4:
        condition = new Condition(_args[2], _args[1], _args[0]);
        failure = setFailure.call(this,_args[3])
        break;
      case 5:
        condition = new Condition(_args[3], _args[2], _args[1], _args[0]);
        failure = setFailure.call(this,_args[4])
        break;
      default:
        condition = new Condition(true);
        failure = this.failure;
    }
    enqueueCheck.call(this,new Check(condition, failure));
    return this;
  };

  Validation.prototype.success = function (callback) {
    return new Success(this, callback);
  };

  var makeInverse = function(rules){
    var not = {};
    for (var rule in rules){
      not[rule] = (function(rule){
        return function(val,$field){
          return !rules[rule](val,$field);
        }
      })(rule);
    }
    return not;
  };

  Validation.fromTemplate = (function(){
    var _selectors = (function(){
      return {
        validation: "data-validation"
        , id: "data-validation-id"
        , ref_id: "data-validation-ref-id"
        , message: "data-validation-message"
        , message_match: "data-validation-match"
        , matchers: "data-validation-matchers"
        , ref_matchers: "data-validation-ref-matchers"

      }
    })();

    var flatArray = function(data){
      return Array.prototype.concat.apply([],data.map(function(val){
        return val;
      }));
    };

    var createMatcher = function(matchers){
      var getMatchers;
      try {
        getMatchers = new Function("Validation","Matchers", "return " + matchers);
      } catch (e) {
        getMatchers = function () {
          return [function () {
            console.log("Validation matcher not proper", matchers);
            return false;
          }];
        }
      }
      return getMatchers;
    };

    var TemplateValidation = function(config){
      //$.extend(true,this,config);
      this.$container = config.$container;
      this.Matchers = $.extend({},config.matchers);
      this.Matchers.not = makeInverse(config.matchers);
      this.onValidation = config.onValidation || this.validationHandler;
      this.onFailure = config.onFailure || this.failureHandler;
      this.selectors = $.extend(true,$.extend({},_selectors),config.selectors);
      this.validation = new Validation("all");
      var _self = this;
      this.$container.find("["+_self.selectors.validation+"]").each(function(){
        var $validation = $(this);
        _self.onValidation.call(_self,$validation);
        var validation = new Validation($validation.attr(_self.selectors.validation));
        $validation.find("["+ _self.selectors.id +"]").each(function(){
          _self.validateField(validation,$validation,$(this));
        });
        _self.validation.check(validation,function(val){
          return val.result;
        },function(condition){
          return condition.value.failures;
        });
        $.extend(true,_self.validation.values,validation.values);
      });
      this.validation.failures = flatArray(this.validation.failures);
      return this.validation;
    };

    TemplateValidation.prototype.createValidation = function(validation,props){
      var getMatchers
        , _self = this;
      if (props.matchers) {
        getMatchers = createMatcher(props.matchers);
        getMatchers.call(null, Validation,_self.Matchers).forEach(function (check, index) {
          validation.check({
            id: props.id
            , $field: props.$field
            , match: check
            , value: props.$field.val()
            , failure: _self.onFailure(props,index)
          });
        });
      }
      return validation;
    };

    TemplateValidation.prototype.getFieldProps = function($validation,$field){
      var fieldId = $field.attr(this.selectors.id);
      var fieldRefId = $field.attr(this.selectors.ref_id);
      var fieldProps = {
        $container: this.$container
        , $validation: $validation
        , id: fieldId
        , $field: $field
        , $messages: $validation.find("["+ this.selectors.message +"='" + fieldId + "']")
        , matchers: $field.attr(this.selectors.matchers)
      };
      fieldProps.ref = {
        id: fieldRefId
        , $field: this.$container.find("["+ this.selectors.id +"='"+ fieldRefId +"']")
        , matchers: $field.attr(this.selectors.ref_matchers)
      };
      return fieldProps;
    };

    TemplateValidation.prototype.validateField = function(validation,$validation,$field) {
      var $fieldProps = this.getFieldProps($validation,$field);
      if ($fieldProps.ref.id){
        var refValidation = this.createValidation(new Validation(),$fieldProps.ref);
        if(refValidation.result) this.createValidation(validation,$fieldProps);
      } else this.createValidation(validation,$fieldProps);
    };

    TemplateValidation.prototype.validationHandler = function($validation){
      $validation.find("["+ this.selectors.message +"]").css("display", "none");
    };

    TemplateValidation.prototype.failureHandler = function(props,index){
      var _self = this;
      return function(condition) {
        if (props.$messages){
          props.$messages.filter(function () {
            return $(this).attr(_self.selectors.message_match) == index;
          }).css("display", "block");
        }
      }
    };

    return function($container,matchers,onvalidation,onfailure,selectors){
      var config = {
        $container: $container
        , matchers: matchers
        , onvalidation: onvalidation
        , onfailure: onfailure
        , selectors: selectors
      };
      if (arguments.length==1 && typeof arguments[0] === "object" && !(arguments[0] instanceof $)) $.extend(true,config,arguments[0]);
      return new TemplateValidation(config);
    }
  })();

  Validation.matchers = {
    isEmailValid: function(val) {
      return /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(val);
    }
    , isNotEmpty: function(val){
    if (val===undefined || val===null ) return false;
    return /^(?=\s*\S).*$/.test(val);
  },
    isChecked: function(val,$field){
      return $field.prop("checked");
    }
  };

  Validation.matchers.not = makeInverse(Validation.matchers);

  return Validation;
})();
return {
    FormManager: FormManager,
    FormStep: FormStep,
    Resolver: Resolver,
    Validation: Validation
};
});
}).apply(window);/**!!<[helper.form-manager]!!**/
/**!![helper.gallery]>!!**/
(function(){
registerHelper("gallery", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var Gallery = function() {
    "use strict";

    function Gallery(config) {
        this.Helpers = new app.helpers();

        this.config = config;

        this.config.defaultItem = this.config.defaultItem || 0;
        this.currentItem = this.config.defaultItem;
        this.$itemScope = $(this.config.scope);
        this.navigationCentered = this.config.navigationCentered;
        this.$thumbnailScope = this.$itemScope.children(".thumbnails");

        if (this.$thumbnailScope) {
            this.$thumbnailItems = this.$thumbnailScope.find(".slides > li");
            this.$thumbnails = this.$thumbnailItems.find("a");
            this.maxThumbnailsPerPage = 
                this.$thumbnailItems.filter(":first").children("a").length;
        }
        this.init();
    }

    $__Object$defineProperties(Gallery.prototype, {
        init: {
            value: function() {
                var $__arguments = arguments;
                if (this.$thumbnailScope) {
                    this.toggleThumbnail();

                    this.thumbnailCarousel = new (this.Helpers.carousel)({
                        scope: this.$thumbnailScope.find(".slides").parent(),
                        renderPagination: false,
                        rotationDuration: this.config.thumbnailRotationDuration,
                        onItemNavigateStart: function(itemIndex) {
                            if (this.config.onThumbnailNavigateStart) {
                                this.config.onThumbnailNavigateStart.apply(this, [
                                    itemIndex
                                ]);
                            }
                        }.bind(this)
                    });

                    this.$thumbnails.each(function(index, element) {
                        $(element).attr("data-id", index);
                    });

                    this.$thumbnails.on("click", function(e) {
                        e.preventDefault();

                        var $this = $(e.currentTarget),
                            index = $this.attr("data-id");

                        this.itemCarousel.navigateTo(index);
                    }.bind(this));
                }

                this.itemCarousel = new (this.Helpers.carousel)({
                    scope: this.$itemScope,
                    showInfo: this.config.showInfo,
                    renderPagination: false,
                    rotationDuration: this.config.itemRotationDuration,
                    defaultItem: this.config.defaultItem,
                    usePixels: this.config.usePixels,
                    onItemNavigateStart: function(itemIndex) {
                        this.currentItem = itemIndex;

                        if (this.$thumbnailScope) {
                            var thumbnailPage = this.getThumbnailPage(itemIndex);

                            this.thumbnailCarousel.navigateTo(thumbnailPage);

                            this.toggleThumbnail();
                        }

                        if (this.config.onItemNavigateStart) {
                            this.config.onItemNavigateStart.apply(this, [
                                itemIndex
                            ]);
                        }
                    }.bind(this),
                    onAfterInit: function() {
                        if (this.config.onAfterInit) {
                            this.config.onAfterInit.apply(this, $__arguments);
                        }
                    }.bind(this),
                    navigationCentered: this.navigationCentered
                });

                this.itemCarousel.$items.on("click", function(e) {
                    if (this.config.onSlideClick) {
                        e.preventDefault();
                        this.config.onSlideClick.apply(this, [e, this.currentItem]);
                    }
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        getThumbnailPage: {
            value: function(index) {
                return Math.floor(index / this.maxThumbnailsPerPage);
            },

            enumerable: false,
            writable: true
        },

        getItemCount: {
            value: function() {
                return this.itemCarousel.getItemCount();
            },

            enumerable: false,
            writable: true
        },

        toggleThumbnail: {
            value: function() {
                this.$thumbnails.removeClass("selected");
                $(this.$thumbnails.get(this.currentItem)).addClass("selected");
            },

            enumerable: false,
            writable: true
        }
    });

    return Gallery;
}();

return Gallery;
});
}).apply(window);/**!!<[helper.gallery]!!**/
/**!![helper.gallery-overlay]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_gallery"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, buffer = "        <li>\n            <div class=\"content\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.youTube : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.program(4, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "                <div class=\"description\">";
  stack1 = lambda((depth0 != null ? depth0.description : depth0), depth0);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</div>\n            </div>\n        </li>\n";
},"2":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                <div class=\"video-wrapper\">\n                    <div class=\"video-bg-img\" style=\"display: none; background-image : url(https://img.youtube.com/vi/"
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "/0.jpg)\" ></div>\n\n                    <img title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" alt=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" data-media=\"https://img.youtube.com/vi/"
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "/0.jpg\" data-video=\"true\" data-render-video=\""
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "\">\n                    <a href=\"#\" class=\"video-link\"></a>\n                    <div class=\"player-store\"></div>\n                </div>\n";
},"4":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                <img title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" alt=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" data-media=\""
    + escapeExpression(lambda((depth0 != null ? depth0.image : depth0), depth0))
    + "\">\n";
},"6":function(depth0,helpers,partials,data) {
  var stack1, buffer = "                <li>\n";
  stack1 = helpers.each.call(depth0, depth0, {"name":"each","hash":{},"fn":this.program(7, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                </li>\n";
},"7":function(depth0,helpers,partials,data) {
  var stack1, buffer = "                    <a href=\"javascript:\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.youTube : depth0), {"name":"if","hash":{},"fn":this.program(8, data),"inverse":this.program(10, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                    </a>\n";
},"8":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        <img data-media=\"https://img.youtube.com/vi/"
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "/0.jpg\" data-video=\"true\">\n                        <div class=\"video-bg-img\" style=\"display: none; background-image : url(https://img.youtube.com/vi/"
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "/0.jpg)\" ></div>\n";
},"10":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        <img data-media=\""
    + escapeExpression(lambda((depth0 != null ? depth0.image : depth0), depth0))
    + "\">\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "<div class=\"gallery\" data-gallery-id=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\">\n    <div class=\"gallery-details slides-wrapper\">\n        <h2 class=\"title\">"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</h2>\n        <div class=\"description\">";
  stack1 = ((helper = (helper = helpers.description || (depth0 != null ? depth0.description : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"description","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  buffer += "</div>\n    </div>\n    <ul class=\"slides\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "    </ul>\n    <div class=\"thumbnails\">\n            <ul class=\"slides\">\n";
  stack1 = ((helpers.grouped_each || (depth0 && depth0.grouped_each) || helperMissing).call(depth0, 5, (depth0 != null ? depth0.items : depth0), {"name":"grouped_each","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "            </ul>\n        </div>\n    <div class=\"info\"></div>\n</div>";
},"useData":true});
this["templates"]["_ie8"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"yt-notification\">\n	<div class=\"yt-inner-wrapper\">\n		<p>"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</p>\n		<span>"
    + escapeExpression(((helper = (helper = helpers.details || (depth0 != null ? depth0.details : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"details","hash":{},"data":data}) : helper)))
    + "</span>\n		<ul class=\"icon-set\">\n			<li class=\"browser ie\">\n				<div class=\"icon\"></div>\n				<a href=\"https://windows.microsoft.com/en-GB/internet-explorer/download-ie\">INTERNET EXPLORER</a>\n			</li>\n			<li class=\"browser chrome\">\n				<div class=\"icon\"></div>\n				<a href=\"https://www.google.com/chrome/browser/desktop/\">GOOGLE CHROME</a>\n			</li>\n			<li class=\"browser firefox\">\n				<div class=\"icon\"></div>\n				<a href=\"https://www.mozilla.org/en-GB/firefox/new/\">FIREFOX</a>\n			</li>\n		</ul>\n	</div>\n</div>\n\n\n\n";
},"useData":true});
this["templates"]["_info"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"info\">\n    <span class=\"current\">"
    + escapeExpression(((helper = (helper = helpers.current || (depth0 != null ? depth0.current : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"current","hash":{},"data":data}) : helper)))
    + "</span>\n    <span class=\"total\">of "
    + escapeExpression(((helper = (helper = helpers.total || (depth0 != null ? depth0.total : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"total","hash":{},"data":data}) : helper)))
    + "</span>\n</div>";
},"useData":true});
this["templates"]["_tabs"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + " data-gallery-id=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\"><a title=\""
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "\" href=\"#\">"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</a></li>\n";
},"2":function(depth0,helpers,partials,data) {
  return "class=\"selected\"";
  },"4":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += " data-gallery-id=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\">";
  stack1 = ((helper = (helper = helpers.content || (depth0 != null ? depth0.content : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"content","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"tabs-select-wrapper\">\n	<a href=\"#\" class=\"tabs-select\" title=\"Open galleries select menu\"></a>\n</div>\n<ul class=\"helper-tabs level-1\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "</ul>\n<ul class=\"helper-tabs level-2\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</ul>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.gallery-overlay.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("gallery-overlay", function(application) {
/*
 * @module GalleryOverlay
 */

/**
 * @class GalleryOverlay
 * @classdesc Renders a tabbed gallery inside an overlay.
 *            This class depends on the following Helpers and Services.
 *                Helpers: overlay, gallery, tabs.
 *                Services: pagetools, youtubeIframeApi.
 */
//***********************helperTest
var $__Object$defineProperties = Object.defineProperties;

var GalleryOverlay = function() {
    "use strict";

    function GalleryOverlay(config) {
        var defaultConfig = {
            scope: null,
            autoplay: true
        };
        this.Services = new app.services();
        this.Helpers = new app.helpers();
        this.pagetools = this.Services.pagetools;
        this._window = this.pagetools.window._element[0];
        this.Templates = {
            _gallery: this.Services.templateService.templates("helper.gallery-overlay._gallery"),
            _tabs: this.Services.templateService.templates("helper.gallery-overlay._tabs"),
            _info: this.Services.templateService.templates("helper.gallery-overlay._info"),
            _ie8: this.Services.templateService.templates("helper.gallery-overlay._ie8")
        };

        this.config = $.extend({}, defaultConfig, config);
        this.targetItemOptions = {};
        this.currentItem = 0;
        this.usePixels = false;
        this.clickedGalleryIndex = 0;
        this.init();
    }

    $__Object$defineProperties(GalleryOverlay.prototype, {
        init: {
            value: function() {
                this.namespace = "HelperGalleryOverlay: ";
                this.getGalleryData();
            },

            enumerable: false,
            writable: true
        },

        getGalleryData: {
            value: function() {
                var $scope = this.config.scope,
                    $galleryButtons,
                    windowProtocol = this._window.location.protocol,
                    windowHost = this._window.location.host,
                    apiUrl = windowProtocol + "//" + windowHost + "/{{apiLocation}}";

                try {
                    if ($scope) {
                        $galleryButtons = $scope.find(".open-gallery-overlay");
                        if (!!$galleryButtons.length) {
                            $galleryButtons.on("click", function(e) {
                                e.preventDefault();

                                this.usePixels = $(e.target).data("use-pixels");
                                var $this = $(e.currentTarget).is("a") ? $(e.currentTarget) : $(e.currentTarget).find("a"),
                                    feedUrl = apiUrl.replace("{{apiLocation}}", $this.attr("href"));

                                feedUrl = feedUrl.match(/\?/) ? feedUrl + "&json=1" : feedUrl + "?json=1";
                                this.getData(feedUrl)
                                    .done(function(data) {
                                    if (data.items) {
                                        this.parseTargetItem(data);
                                        this.renderGallery(data);
                                    } else {
                                        console.log("Feed does not have galleries");
                                    }
                                }.bind(this))
                                    .fail(function(data) {
                                    console.log(this.namespace + "Galleries feed request failed");
                                }.bind(this));
                            }.bind(this));
                        } else {}
                    } else {}
                } catch (exception) {
                    console.log(moduleLog);
                    throw new Error(exception);
                }
            },

            enumerable: false,
            writable: true
        },

        getData: {
            value: function(dataUrl) {
                return this._window.$.ajax(dataUrl);
            },

            enumerable: false,
            writable: true
        },

        parseTargetItem: {
            value: function(data) {
                // Store the clicked target to select correspondent gallery or item
                var targetId = data.target_id || 0;
                for (var i = 0; i < data.items.length; i++) {
                    var currentGallery = data.items[i];
                    if (currentGallery.hasOwnProperty("id") && targetId === currentGallery.id) {
                        this.targetItemOptions.galleryId = currentGallery.id;
                        return;
                    }
                    if (currentGallery.hasOwnProperty("items")) {
                        for (var j = 0; j < currentGallery.items.length; j++) {
                            if (currentGallery.items[j].hasOwnProperty("id") && targetId === currentGallery.items[j].id) {
                                this.targetItemOptions.galleryId = currentGallery.id;
                                this.targetItemOptions.itemIndex = j;
                                return;
                            }
                        }
                    }
                }
                this.targetItemOptions = {
                    galleryId: 0,
                    itemIndex: 0
                };
            },

            enumerable: false,
            writable: true
        },

        renderGallery: {
            value: function(galleryData) {
                if (typeof galleryData === "object") {
                    var tabsTemplate = {
                            "items": []
                        };
                    // Render each gallery template and add it to tabsTemplate
                    for (var i, i = 0; i < galleryData.items.length; i++) {
                        var temp = {
                            title: galleryData.items[i].title,
                            id: galleryData.items[i].id,
                            content: this.Templates._gallery(galleryData.items[i])
                        };
                        tabsTemplate.items.push(temp);
                    }

                    // Render the tabs template with the tabsTemplate object, that contains the galleries html
                    var galleryTemplate = this.Templates._tabs(tabsTemplate);

                    // Create config to pass to the overlay helper. Contains the galleryTemplate, which has the tabsTemplate html.
                    // The tabsTemplate html already has the galleries html inside each tab.
                    var overlayConfig = {
                            moduleClass: "helper-gallery-overlay",
                            afterInit: function(element) {
                                if (element) {
                                    var $element = $(element);
                                    $(".overlay-helper").addClass("overlayBlack");
                                    $element.html(galleryTemplate);
                                    this.startGallery.call(this);
                                }
                            }.bind(this)
                        };
                    // Instantiate the overlay. After init, it will call the startGallery method to bind events.
                    this.overlayHelper = new (this.Helpers.overlay)(overlayConfig);
                } else {
                    console.log(this.namespace + "Galleries feed is undefined");
                }
            },

            enumerable: false,
            writable: true
        },

        startGallery: {
            value: function() {
                var $galleries;
                // Set the overlay scope element
                this.$overlayScope = this.overlayHelper.$elContent;

                // Get all the galleries inside the overlay element
                $galleries = this.$overlayScope.find(".gallery");

                // If the gallery overlay has only 1 gallery
                if ($galleries.length === 1) {
                    this.$overlayScope.addClass("single-gallery");
                }

                // Go through each gallery element in the overlay.
                // On each, instantiate a new gallery to bind all events and build it as a gallery
                $galleries.each(function(index, element) {
                    var $this = $(element),
                        $slides = $this.find(".slides"),
                        $slidesWrapper,
                        config = {
                            scope: $this,
                            defaultItem: parseInt($this.attr("data-gallery-id")) === parseInt(this.targetItemOptions.galleryId) ? parseInt(this.targetItemOptions.itemIndex) : 0,
                            itemCount: $slides.first().find("li").length,
                            usePixels: this.usePixels,
                            onItemNavigateStart: function(itemIndex) {
                                this.currentItem = itemIndex;

                                this.refreshInfo.call(this, config.scope, config.itemCount);
                            }.bind(this)
                        };

                    element.gallery = new (this.Helpers.gallery)(config);

                    // In case there's only 1 item in the gallery
                    if (config.itemCount === 1) {
                        $slidesWrapper = $slides;
                        $this.addClass("single-item");
                    } else {
                        $slidesWrapper = $this.find(".slides-wrapper");
                    }

                    // Refresh info displays the current item/total count in the page
                    // Generates the template to each gallery
                    this.refreshInfo(config.scope, config.itemCount);
                }.bind(this));

                this.startTabs();
            },

            enumerable: false,
            writable: true
        },

        refreshInfo: {
            value: function($scope, itemCount) {
                this.$info = $scope.children(".info");

                var infoHtml = this.Templates._info({
                    current: this.integerToTwoDigits(this.currentItem + 1),
                    total: this.integerToTwoDigits(itemCount)
                });

                if (!this.$info.length) {
                    $scope.append(infoHtml);
                } else {
                    this.$info.replaceWith(infoHtml);
                }
            },

            enumerable: false,
            writable: true
        },

        integerToTwoDigits: {
            value: function(integer) {
                return integer < 10 ? "0" + integer : integer.toString();
            },

            enumerable: false,
            writable: true
        },

        startTabs: {
            value: function() {
                var $tabSet = this.$overlayScope.find(".helper-tabs.level-1"),
                    $tabContentSet = this.$overlayScope.find(".helper-tabs.level-2"),
                    $tabs = $tabSet.children("li"),
                    tabOpenedByDefault = 0;

                // Gets the gallery corresponding to the clicked link to open by default
                $tabs.each(function(index, element) {
                    if ($(element).attr("data-gallery-id") === this.targetItemOptions.galleryId) {
                        tabOpenedByDefault = index;
                    }
                }.bind(this));

                this.tabsConfig = {
                    scope: this.$overlayScope,
                    defaultTabIndex: tabOpenedByDefault,
                    mobileAsDropdown: false, // This helper uses a custom implementaion of dropdown - Always keep this as false and don't remove it, because default is true
                    tabSet: $tabSet,
                    tabContentSet: $tabContentSet,
                    tabSelectMenu: this.$overlayScope.find(".tabs-select"),
                    onTabInit: function(index, element) {
                        this.postRenderMedia.call(this, element);
                    }.bind(this)
                };

                new (this.Helpers.tabs)(this.tabsConfig);

                // Gets widths to do post render adjustments
                this.tabSetWidth = this.tabsConfig.tabSet.width();
                this.tabsWidth = this.getTabsWidth($tabs);

                this.setSelectedMobileTab();
                this.startMobileTabs();
            },

            enumerable: false,
            writable: true
        },

        getTabsWidth: {
            value: function($scope) {
                var width = 0;
                $scope.each(function(index, element) {
                    width += $(element).outerWidth(true);
                });
                return width;
            },

            enumerable: false,
            writable: true
        },

        setSelectedMobileTab: {
            value: function($scope) {
                var selectedTabText = $scope ? $scope.text() : this.tabsConfig.tabSet.find(".selected").children().text();
                this.tabsConfig.tabSelectMenu.text(selectedTabText);
            },

            enumerable: false,
            writable: true
        },

        startMobileTabs: {
            value: function() {
                this.bindMobileTabsEvents();
                this.toggleDesktopDropdownTabs();
            },

            enumerable: false,
            writable: true
        },

        bindMobileTabsEvents: {
            value: function() {
                this.tabsConfig.tabSelectMenu.on("click", function(event) {
                    event.preventDefault();
                    $(event.currentTarget).toggleClass("opened");
                    this.tabsConfig.tabSet.toggleClass("mobile-visible");
                }.bind(this));

                // When a tab is selected on dropdown mode, closes the dropdown
                this.tabsConfig.tabSet.find("a").on("click.tabSelectMenu", function(event) {
                    event.preventDefault();
                    this.setSelectedMobileTab($(event.currentTarget));
                    this.tabsConfig.tabSelectMenu.removeClass("opened");
                    this.tabsConfig.tabSet.removeClass("mobile-visible");
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        postRenderMedia: {
            value: function($scope) {
                if (!$scope.attr("data-media-rendered")) {
                    $scope.find("img").each(function(index, element) {
                        var $this = $(element),
                            mediaData = $this.data("media");

                        if ($this.attr("data-video") && $this.data("render-video")) {
                            this.bindVideoEvents($this.next(), $this.data("render-video"));
                        }
                        $this.attr("src", mediaData);
                    }.bind(this));
                    $scope.attr("data-media-rendered", "true");
                }
            },

            enumerable: false,
            writable: true
        },

        toggleDesktopDropdownTabs: {
            value: function() {
                if (this.tabSetWidth < this.tabsWidth) {
                    this.$overlayScope.addClass("dropdown-tabs");
                } else {
                    this.$overlayScope.removeClass("dropdown-tabs");
                }
            },

            enumerable: false,
            writable: true
        },

        bindVideoEvents: {
            value: function($scope, videoId) {
                if(!$("html").hasClass("ie8")){
                    var $navButtons = this.overlayHelper.$element.find(".nav-button");
                    $scope.on("click", function(e) {
                        e.preventDefault();

                        $scope.closest(".video-wrapper").addClass("playing");
                        $scope.prev().hide();
                        $scope.hide();
                        this.Services.youtubeIframeApi
                            .then(function(YT) {
                            return YT.createPlayer($scope.siblings(".player-store")[0], videoId);
                        }).then(function(player) {
                            if (this.config.autoplay) {
                                player.addEventListener("onStateChange", function(event) {
                                    switch(event.data) {
                                        case 1:
                                            $navButtons.on("click.videoPlaying", function(clickEvent) {
                                                event.target.pauseVideo();
                                            });
                                            break;
                                        case 2:
                                            $navButtons.off("click.videoPlaying");
                                            break;
                                    }
                                });
                                player.playVideo();
                            }
                        }.bind(this))["catch"](function(err) {
                            throw new Error(err);
                        });
                    }.bind(this));
                }
                else{
                    var ie8Message;
                    if($("body").hasClass("en")){
                        ie8Message = this.Templates._ie8({
                        title: "We have detected you are using software unsupported by the YouTube online video service.",
                        details: "Youtube works with a wide range of browsers, however if you would like to use many of our features, please upgrade to a modern, fully supported browser. Find the latest versions of browsers supported by Youtube below:"   
                        });
                    }
                    else{
                        ie8Message = this.Templates._ie8({
                        title: "ご使用になっているブラウザはYoutubeによるサポートが終了していますので動画を閲覧頂くことが出来ません。",
                        details: "以下のリンクよりブラウザのアップグレードをご検討ください。"             
                        });
                    }
                    $(".video-wrapper").html(ie8Message);
                }
            },

            enumerable: false,
            writable: true
        }
    });

    return GalleryOverlay;
}();

return GalleryOverlay;
});
}).apply(window);/**!!<[helper.gallery-overlay]!!**/
/**!![helper.grouped-list]>!!**/
(function(){
registerHelper("grouped-list", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var GroupedList = function() {
    "use strict";

    function GroupedList(config) {
        this.Helpers = new app.helpers();

        this.config = config;

        this.init();
    }

    $__Object$defineProperties(GroupedList.prototype, {
        init: {
            value: function() {
                if(this.config.renderAs === "tabbed") {
                    var tabs = new (this.Helpers.tabs)({
                        tabCollection: this.config.tabCollection,
                        onTabClick: this.config.onTabClick,
                        afterInit: this.config.afterInit,
                        scope: this.config.scope
                    });
                }
            },

            enumerable: false,
            writable: true
        }
    });

    return GroupedList;
}();

return GroupedList;
});
}).apply(window);/**!!<[helper.grouped-list]!!**/
/**!![helper.leaflet-map]>!!**/
(function(){
registerHelper("leaflet-map", function(application) {
var isIE11 = !!navigator.userAgent.match(/Trident.*rv[ :]*11\./);

if (isIE11) {
    L_PREFER_CANVAS = true;
    L_DISABLE_3D = true;
}
/*
 Leaflet 0.8-dev ("98bf925"), a JS library for interactive maps. http://leafletjs.com
 (c) 2010-2015 Vladimir Agafonkin, (c) 2010-2011 CloudMade
*/
!function(t,e,i){
 function n(){
  var e=t.L;o.noConflict=function(){
   return (t.L=e, this);
  },t.L=o;
 }var o={version: "0.8-dev"};"object"==typeof module&&"object"==typeof module.exports?module.exports=o:"function"==typeof define&&define.amd&&define(o),"undefined"!=typeof t&&n(),o.Util={extend: function(t){
  var e,i,n,o;for(i=1,n=arguments.length;n>i;i++){
   o=arguments[i];for(e in o)t[e]=o[e];
  }return t;
 },create: Object.create||function(){
  function t(){}return function(e){
   return (t.prototype=e, new t);
  }
 }(),bind: function(t,e){
  var i=Array.prototype.slice;if(t.bind)return t.bind.apply(t,i.call(arguments,1));var n=i.call(arguments,2);return function(){
   return t.apply(e,n.length?n.concat(i.call(arguments)):arguments);
  }
 },stamp: function(t){
  return (t._leaflet_id=t._leaflet_id||++o.Util.lastId, t._leaflet_id);
 },lastId: 0,throttle: function(t,e,i){
  var n,o,s,a;return (a=function(){
   n=!1,o&&(s.apply(i,o),o=!1);
  }, s=function(){
   n?o=arguments:(t.apply(i,arguments),setTimeout(a,e),n=!0);
  });
 },wrapNum: function(t,e,i){
  var n=e[1],o=e[0],s=n-o;return t===n&&i?t:((t-o)%s+s)%s+o;
 },falseFn: function(){
  return!1;
 },formatNum: function(t,e){
  var i=Math.pow(10,e||5);return Math.round(t*i)/i;
 },trim: function(t){
  return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"");
 },splitWords: function(t){
  return o.Util.trim(t).split(/\s+/);
 },setOptions: function(t,e){
  t.hasOwnProperty("options")||(t.options=t.options?o.Util.create(t.options):{});for(var i in e)t.options[i]=e[i];return t.options;
 },getParamString: function(t,e,i){
  var n=[];for(var o in t)n.push(encodeURIComponent(i?o.toUpperCase():o)+"="+encodeURIComponent(t[o]));return(e&&-1!==e.indexOf("?")?"&":"?")+n.join("&");
 },template: function(t,e){
  return t.replace(o.Util.templateRe,function(t,n){
   var o=e[n];if(o===i)throw new Error("No value provided for variable "+t);return("function"==typeof o&&(o=o(e)), o);
  });
 },templateRe: /\{ *([\w_]+) *\}/g,isArray: Array.isArray||function(t){
  return"[object Array]"===Object.prototype.toString.call(t);
 },emptyImageUrl: "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="},function(){
  function e(e){
   return t["webkit"+e]||t["moz"+e]||t["ms"+e];
  }function i(e){
   var i=+new Date,o=Math.max(0,16-(i-n));return (n=i+o, t.setTimeout(e,o));
  }var n=0,s=t.requestAnimationFrame||e("RequestAnimationFrame")||i,a=t.cancelAnimationFrame||e("CancelAnimationFrame")||e("CancelRequestAnimationFrame")||function(e){
   t.clearTimeout(e);
  };o.Util.requestAnimFrame=function(e,n,a){
   return a&&s===i?void e.call(n):s.call(t,o.bind(e,n));
  },o.Util.cancelAnimFrame=function(e){
   e&&a.call(t,e);
  }
 }(),o.extend=o.Util.extend,o.bind=o.Util.bind,o.stamp=o.Util.stamp,o.setOptions=o.Util.setOptions,o.Class=function(){},o.Class.extend=function(t){
  var e=function(){
   this.initialize&&this.initialize.apply(this,arguments),this.callInitHooks();
  },i=e.__super__=this.prototype,n=o.Util.create(i);n.constructor=e,e.prototype=n;for(var s in this)this.hasOwnProperty(s)&&"prototype"!==s&&(e[s]=this[s]);return (t.statics&&(o.extend(e,t.statics),delete t.statics), t.includes&&(o.Util.extend.apply(null,[n].concat(t.includes)),delete t.includes), n.options&&(t.options=o.Util.extend(o.Util.create(n.options),t.options)), o.extend(n,t), n._initHooks=[], n.callInitHooks=function(){
   if(!this._initHooksCalled){
    i.callInitHooks&&i.callInitHooks.call(this),this._initHooksCalled=!0;for(var t=0,e=n._initHooks.length;e>t;t++)n._initHooks[t].call(this);
   }
  }, e);
 },o.Class.include=function(t){
  o.extend(this.prototype,t);
 },o.Class.mergeOptions=function(t){
  o.extend(this.prototype.options,t);
 },o.Class.addInitHook=function(t){
  var e=Array.prototype.slice.call(arguments,1),i="function"==typeof t?t:function(){
   this[t].apply(this,e);
  };this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(i);
 },o.Evented=o.Class.extend({on: function(t,e,i){
  if("object"==typeof t)for(var n in t)this._on(n,t[n],e);else{
   t=o.Util.splitWords(t);for(var s=0,a=t.length;a>s;s++)this._on(t[s],e,i);
  }return this;
 },off: function(t,e,i){
  if(t)if("object"==typeof t)for(var n in t)this._off(n,t[n],e);else{
   t=o.Util.splitWords(t);for(var s=0,a=t.length;a>s;s++)this._off(t[s],e,i);
  }else delete this._events;return this;
 },_on: function(t,e,i){
  var n=this._events=this._events||{},s=i&&i!==this&&o.stamp(i);if(s){
   var a=t+"_idx",r=t+"_len",h=n[a]=n[a]||{},l=o.stamp(e)+"_"+s;h[l]||(h[l]={fn: e,ctx: i},n[r]=(n[r]||0)+1);
  }else n[t]=n[t]||[],n[t].push({fn: e});
 },_off: function(t,e,i){
  var n=this._events,s=t+"_idx",a=t+"_len";if(n){
   if(!e)return (delete n[t], delete n[s], void delete n[a]);var r,h,l,u,c,d=i&&i!==this&&o.stamp(i);if(d)c=o.stamp(e)+"_"+d,r=n[s],r&&r[c]&&(u=r[c],delete r[c],n[a]--);else if(r=n[t])for(h=0,l=r.length;l>h;h++)if(r[h].fn===e){
    u=r[h],r.splice(h,1);break;
   }u&&(u.fn=o.Util.falseFn);
  }
 },fire: function(t,e,i){
  if(!this.listens(t,i))return this;var n=o.Util.extend({},e,{type: t,target: this}),s=this._events;if(s){
   var a,r,h,l,u=s[t+"_idx"];if(s[t])for(h=s[t].slice(),a=0,r=h.length;r>a;a++)h[a].fn.call(this,n);for(l in u)u[l].fn.call(u[l].ctx,n);
  }return (i&&this._propagateEvent(n), this);
 },listens: function(t,e){
  var i=this._events;if(i&&(i[t]||i[t+"_len"]))return!0;if(e)for(var n in this._eventParents)if(this._eventParents[n].listens(t,e))return!0;return!1;
 },once: function(t,e,i){
  if("object"==typeof t){
   for(var n in t)this.once(n,t[n],e);return this;
  }var s=o.bind(function(){
   this.off(t,e,i).off(t,s,i);
  },this);return this.on(t,e,i).on(t,s,i);
 },addEventParent: function(t){
  return (this._eventParents=this._eventParents||{}, this._eventParents[o.stamp(t)]=t, this);
 },removeEventParent: function(t){
  return (this._eventParents&&delete this._eventParents[o.stamp(t)], this);
 },_propagateEvent: function(t){
  for(var e in this._eventParents)this._eventParents[e].fire(t.type,o.extend({layer: t.target},t),!0);
 }});var s=o.Evented.prototype;s.addEventListener=s.on,s.removeEventListener=s.clearAllEventListeners=s.off,s.addOneTimeEventListener=s.once,s.fireEvent=s.fire,s.hasEventListeners=s.listens,o.Mixin={Events: s},function(){
  var i=navigator.userAgent.toLowerCase(),n=e.documentElement,s="ActiveXObject"in t,a=-1!==i.indexOf("webkit"),r=-1!==i.indexOf("phantom"),h=-1!==i.search("android [23]"),l=-1!==i.indexOf("chrome"),u="undefined"!=typeof orientation,c=navigator.msPointerEnabled&&navigator.msMaxTouchPoints&&!t.PointerEvent,d=t.PointerEvent&&navigator.pointerEnabled&&navigator.maxTouchPoints||c,m=s&&"transition"in n.style,_="WebKitCSSMatrix"in t&&"m11"in new t.WebKitCSSMatrix&&!h,p="MozPerspective"in n.style,f="OTransition"in n.style,v=!t.L_NO_TOUCH&&!r&&(d||"ontouchstart"in t||t.DocumentTouch&&e instanceof t.DocumentTouch);o.Browser={ie: s,ielt9: s&&!e.addEventListener,webkit: a,gecko: -1!==i.indexOf("gecko")&&!a&&!t.opera&&!s,android: -1!==i.indexOf("android"),android23: h,chrome: l,safari: !l&&-1!==i.indexOf("safari"),ie3d: m,webkit3d: _,gecko3d: p,opera3d: f,any3d: !t.L_DISABLE_3D&&(m||_||p||f)&&!r,mobile: u,mobileWebkit: u&&a,mobileWebkit3d: u&&_,mobileOpera: u&&t.opera,touch: !!v,msPointer: !!c,pointer: !!d,retina: (t.devicePixelRatio||t.screen.deviceXDPI/t.screen.logicalXDPI)>1}
 }(),o.Point=function(t,e,i){
  this.x=i?Math.round(t):t,this.y=i?Math.round(e):e;
 },o.Point.prototype={clone: function(){
  return new o.Point(this.x,this.y);
 },add: function(t){
  return this.clone()._add(o.point(t));
 },_add: function(t){
  return (this.x+=t.x, this.y+=t.y, this);
 },subtract: function(t){
  return this.clone()._subtract(o.point(t));
 },_subtract: function(t){
  return (this.x-=t.x, this.y-=t.y, this);
 },divideBy: function(t){
  return this.clone()._divideBy(t);
 },_divideBy: function(t){
  return (this.x/=t, this.y/=t, this);
 },multiplyBy: function(t){
  return this.clone()._multiplyBy(t);
 },_multiplyBy: function(t){
  return (this.x*=t, this.y*=t, this);
 },round: function(){
  return this.clone()._round();
 },_round: function(){
  return (this.x=Math.round(this.x), this.y=Math.round(this.y), this);
 },floor: function(){
  return this.clone()._floor();
 },_floor: function(){
  return (this.x=Math.floor(this.x), this.y=Math.floor(this.y), this);
 },ceil: function(){
  return this.clone()._ceil();
 },_ceil: function(){
  return (this.x=Math.ceil(this.x), this.y=Math.ceil(this.y), this);
 },distanceTo: function(t){
  t=o.point(t);var e=t.x-this.x,i=t.y-this.y;return Math.sqrt(e*e+i*i);
 },equals: function(t){
  return (t=o.point(t), t.x===this.x&&t.y===this.y);
 },contains: function(t){
  return (t=o.point(t), Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y));
 },toString: function(){
  return"Point("+o.Util.formatNum(this.x)+", "+o.Util.formatNum(this.y)+")";
 }},o.point=function(t,e,n){
  return t instanceof o.Point?t:o.Util.isArray(t)?new o.Point(t[0],t[1]):t===i||null===t?t:new o.Point(t,e,n);
 },o.Bounds=function(t,e){
  if(t)for(var i=e?[t,e]:t,n=0,o=i.length;o>n;n++)this.extend(i[n]);
 },o.Bounds.prototype={extend: function(t){
  return (t=o.point(t), this.min||this.max?(this.min.x=Math.min(t.x,this.min.x),this.max.x=Math.max(t.x,this.max.x),this.min.y=Math.min(t.y,this.min.y),this.max.y=Math.max(t.y,this.max.y)):(this.min=t.clone(),this.max=t.clone()), this);
 },getCenter: function(t){
  return new o.Point((this.min.x+this.max.x)/2,(this.min.y+this.max.y)/2,t);
 },getBottomLeft: function(){
  return new o.Point(this.min.x,this.max.y);
 },getTopRight: function(){
  return new o.Point(this.max.x,this.min.y);
 },getSize: function(){
  return this.max.subtract(this.min);
 },contains: function(t){
  var e,i;return (t="number"==typeof t[0]||t instanceof o.Point?o.point(t):o.bounds(t), t instanceof o.Bounds?(e=t.min,i=t.max):e=i=t, e.x>=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y);
 },intersects: function(t){
  t=o.bounds(t);var e=this.min,i=this.max,n=t.min,s=t.max,a=s.x>=e.x&&n.x<=i.x,r=s.y>=e.y&&n.y<=i.y;return a&&r;
 },isValid: function(){
  return!(!this.min||!this.max);
 }},o.bounds=function(t,e){
  return!t||t instanceof o.Bounds?t:new o.Bounds(t,e);
 },o.Transformation=function(t,e,i,n){
  this._a=t,this._b=e,this._c=i,this._d=n;
 },o.Transformation.prototype={transform: function(t,e){
  return this._transform(t.clone(),e);
 },_transform: function(t,e){
  return (e=e||1, t.x=e*(this._a*t.x+this._b), t.y=e*(this._c*t.y+this._d), t);
 },untransform: function(t,e){
  return (e=e||1, new o.Point((t.x/e-this._b)/this._a,(t.y/e-this._d)/this._c));
 }},o.DomUtil={get: function(t){
  return"string"==typeof t?e.getElementById(t):t;
 },getStyle: function(t,i){
  var n=t.style[i]||t.currentStyle&&t.currentStyle[i];if((!n||"auto"===n)&&e.defaultView){
   var o=e.defaultView.getComputedStyle(t,null);n=o?o[i]:null;
  }return"auto"===n?null:n;
 },create: function(t,i,n){
  var o=e.createElement(t);return (o.className=i, n&&n.appendChild(o), o);
 },remove: function(t){
  var e=t.parentNode;e&&e.removeChild(t);
 },empty: function(t){
  for(;t.firstChild;)t.removeChild(t.firstChild);
 },toFront: function(t){
  t.parentNode.appendChild(t);
 },toBack: function(t){
  var e=t.parentNode;e.insertBefore(t,e.firstChild);
 },hasClass: function(t,e){
  if(t.classList!==i)return t.classList.contains(e);var n=o.DomUtil.getClass(t);return n.length>0&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(n);
 },addClass: function(t,e){
  if(t.classList!==i)for(var n=o.Util.splitWords(e),s=0,a=n.length;a>s;s++)t.classList.add(n[s]);else if(!o.DomUtil.hasClass(t,e)){
   var r=o.DomUtil.getClass(t);o.DomUtil.setClass(t,(r?r+" ":"")+e);
  }
 },removeClass: function(t,e){
  t.classList!==i?t.classList.remove(e):o.DomUtil.setClass(t,o.Util.trim((" "+o.DomUtil.getClass(t)+" ").replace(" "+e+" "," ")));
 },setClass: function(t,e){
  t.className.baseVal===i?t.className=e:t.className.baseVal=e;
 },getClass: function(t){
  return t.className.baseVal===i?t.className:t.className.baseVal;
 },setOpacity: function(t,e){
  "opacity"in t.style?t.style.opacity=e:"filter"in t.style&&o.DomUtil._setOpacityIE(t,e);
 },_setOpacityIE: function(t,e){
  var i=!1,n="DXImageTransform.Microsoft.Alpha";try{
   i=t.filters.item(n);
  }catch(o){
   if(1===e)return;
  }e=Math.round(100*e),i?(i.Enabled=100!==e,i.Opacity=e):t.style.filter+=" progid:"+n+"(opacity="+e+")";
 },testProp: function(t){
  for(var i=e.documentElement.style,n=0;n<t.length;n++)if(t[n]in i)return t[n];return!1;
 },setTransform: function(t,e,i){
  var n=e||new o.Point(0,0);t.style[o.DomUtil.TRANSFORM]="translate3d("+n.x+"px,"+n.y+"px,0)"+(i?" scale("+i+")":"");
 },setPosition: function(t,e,i){
  t._leaflet_pos=e,o.Browser.any3d&&!i?o.DomUtil.setTransform(t,e):(t.style.left=e.x+"px",t.style.top=e.y+"px");
 },getPosition: function(t){
  return t._leaflet_pos;
 }},function(){
  o.DomUtil.TRANSFORM=o.DomUtil.testProp(["transform","WebkitTransform","OTransform","MozTransform","msTransform"]);var i=o.DomUtil.TRANSITION=o.DomUtil.testProp(["webkitTransition","transition","OTransition","MozTransition","msTransition"]);if(o.DomUtil.TRANSITION_END="webkitTransition"===i||"OTransition"===i?i+"End":"transitionend","onselectstart"in e)o.DomUtil.disableTextSelection=function(){
   o.DomEvent.on(t,"selectstart",o.DomEvent.preventDefault);
  },o.DomUtil.enableTextSelection=function(){
   o.DomEvent.off(t,"selectstart",o.DomEvent.preventDefault);
  };else{
   var n=o.DomUtil.testProp(["userSelect","WebkitUserSelect","OUserSelect","MozUserSelect","msUserSelect"]);o.DomUtil.disableTextSelection=function(){
    if(n){
     var t=e.documentElement.style;this._userSelect=t[n],t[n]="none";
    }
   },o.DomUtil.enableTextSelection=function(){
    n&&(e.documentElement.style[n]=this._userSelect,delete this._userSelect);
   }
  }o.DomUtil.disableImageDrag=function(){
   o.DomEvent.on(t,"dragstart",o.DomEvent.preventDefault);
  },o.DomUtil.enableImageDrag=function(){
   o.DomEvent.off(t,"dragstart",o.DomEvent.preventDefault);
  }
 }(),o.LatLng=function(t,e,n){
  if(isNaN(t)||isNaN(e))throw new Error("Invalid LatLng object: ("+t+", "+e+")");this.lat=+t,this.lng=+e,n!==i&&(this.alt=+n);
 },o.LatLng.prototype={equals: function(t,e){
  if(!t)return!1;t=o.latLng(t);var n=Math.max(Math.abs(this.lat-t.lat),Math.abs(this.lng-t.lng));return(e===i?1e-9:e)>=n;
 },toString: function(t){
  return"LatLng("+o.Util.formatNum(this.lat,t)+", "+o.Util.formatNum(this.lng,t)+")";
 },distanceTo: function(t){
  return o.CRS.Earth.distance(this,o.latLng(t));
 },wrap: function(){
  return o.CRS.Earth.wrapLatLng(this);
 },toBounds: function(t){
  var e=180*t/40075017,i=e/Math.cos(Math.PI/180*this.lat);return o.latLngBounds([this.lat-e,this.lng-i],[this.lat+e,this.lng+i]);
 }},o.latLng=function(t,e,n){
  return t instanceof o.LatLng?t:o.Util.isArray(t)&&"object"!=typeof t[0]?3===t.length?new o.LatLng(t[0],t[1],t[2]):2===t.length?new o.LatLng(t[0],t[1]):null:t===i||null===t?t:"object"==typeof t&&"lat"in t?new o.LatLng(t.lat,"lng"in t?t.lng:t.lon,t.alt):e===i?null:new o.LatLng(t,e,n);
 },o.LatLngBounds=function(t,e){
  if(t)for(var i=e?[t,e]:t,n=0,o=i.length;o>n;n++)this.extend(i[n]);
 },o.LatLngBounds.prototype={extend: function(t){
  var e,i,n=this._southWest,s=this._northEast;if(t instanceof o.LatLng)e=t,i=t;else{
   if(!(t instanceof o.LatLngBounds))return t?this.extend(o.latLng(t)||o.latLngBounds(t)):this;if(e=t._southWest,i=t._northEast,!e||!i)return this;
  }return (n||s?(n.lat=Math.min(e.lat,n.lat),n.lng=Math.min(e.lng,n.lng),s.lat=Math.max(i.lat,s.lat),s.lng=Math.max(i.lng,s.lng)):(this._southWest=new o.LatLng(e.lat,e.lng),this._northEast=new o.LatLng(i.lat,i.lng)), this);
 },pad: function(t){
  var e=this._southWest,i=this._northEast,n=Math.abs(e.lat-i.lat)*t,s=Math.abs(e.lng-i.lng)*t;return new o.LatLngBounds(new o.LatLng(e.lat-n,e.lng-s),new o.LatLng(i.lat+n,i.lng+s));
 },getCenter: function(){
  return new o.LatLng((this._southWest.lat+this._northEast.lat)/2,(this._southWest.lng+this._northEast.lng)/2);
 },getSouthWest: function(){
  return this._southWest;
 },getNorthEast: function(){
  return this._northEast;
 },getNorthWest: function(){
  return new o.LatLng(this.getNorth(),this.getWest());
 },getSouthEast: function(){
  return new o.LatLng(this.getSouth(),this.getEast());
 },getWest: function(){
  return this._southWest.lng;
 },getSouth: function(){
  return this._southWest.lat;
 },getEast: function(){
  return this._northEast.lng;
 },getNorth: function(){
  return this._northEast.lat;
 },contains: function(t){
  t="number"==typeof t[0]||t instanceof o.LatLng?o.latLng(t):o.latLngBounds(t);var e,i,n=this._southWest,s=this._northEast;return (t instanceof o.LatLngBounds?(e=t.getSouthWest(),i=t.getNorthEast()):e=i=t, e.lat>=n.lat&&i.lat<=s.lat&&e.lng>=n.lng&&i.lng<=s.lng);
 },intersects: function(t){
  t=o.latLngBounds(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),s=t.getNorthEast(),a=s.lat>=e.lat&&n.lat<=i.lat,r=s.lng>=e.lng&&n.lng<=i.lng;return a&&r;
 },toBBoxString: function(){
  return[this.getWest(),this.getSouth(),this.getEast(),this.getNorth()].join(",");
 },equals: function(t){
  return t?(t=o.latLngBounds(t),this._southWest.equals(t.getSouthWest())&&this._northEast.equals(t.getNorthEast())):!1;
 },isValid: function(){
  return!(!this._southWest||!this._northEast);
 }},o.latLngBounds=function(t,e){
  return!t||t instanceof o.LatLngBounds?t:new o.LatLngBounds(t,e);
 },o.Projection={},o.Projection.LonLat={project: function(t){
  return new o.Point(t.lng,t.lat);
 },unproject: function(t){
  return new o.LatLng(t.y,t.x);
 },bounds: o.bounds([-180,-90],[180,90])},o.Projection.SphericalMercator={R: 6378137,project: function(t){
  var e=Math.PI/180,i=1-1e-15,n=Math.max(Math.min(Math.sin(t.lat*e),i),-i);return new o.Point(this.R*t.lng*e,this.R*Math.log((1+n)/(1-n))/2);
 },unproject: function(t){
  var e=180/Math.PI;return new o.LatLng((2*Math.atan(Math.exp(t.y/this.R))-Math.PI/2)*e,t.x*e/this.R);
 },bounds: function(){
  var t=6378137*Math.PI;return o.bounds([-t,-t],[t,t]);
 }()},o.CRS={latLngToPoint: function(t,e){
  var i=this.projection.project(t),n=this.scale(e);return this.transformation._transform(i,n);
 },pointToLatLng: function(t,e){
  var i=this.scale(e),n=this.transformation.untransform(t,i);return this.projection.unproject(n);
 },project: function(t){
  return this.projection.project(t);
 },unproject: function(t){
  return this.projection.unproject(t);
 },scale: function(t){
  return 256*Math.pow(2,t);
 },getProjectedBounds: function(t){
  if(this.infinite)return null;var e=this.projection.bounds,i=this.scale(t),n=this.transformation.transform(e.min,i),s=this.transformation.transform(e.max,i);return o.bounds(n,s);
 },wrapLatLng: function(t){
  var e=this.wrapLng?o.Util.wrapNum(t.lng,this.wrapLng,!0):t.lng,i=this.wrapLat?o.Util.wrapNum(t.lat,this.wrapLat,!0):t.lat;return o.latLng(i,e);
 }},o.CRS.Simple=o.extend({},o.CRS,{projection: o.Projection.LonLat,transformation: new o.Transformation(1,0,-1,0),scale: function(t){
  return Math.pow(2,t);
 },distance: function(t,e){
  var i=e.lng-t.lng,n=e.lat-t.lat;return Math.sqrt(i*i+n*n);
 },infinite: !0}),o.CRS.Earth=o.extend({},o.CRS,{wrapLng: [-180,180],R: 6378137,distance: function(t,e){
  var i=Math.PI/180,n=t.lat*i,o=e.lat*i,s=Math.sin(n)*Math.sin(o)+Math.cos(n)*Math.cos(o)*Math.cos((e.lng-t.lng)*i);return this.R*Math.acos(Math.min(s,1));
 }}),o.CRS.EPSG3857=o.extend({},o.CRS.Earth,{code: "EPSG:3857",projection: o.Projection.SphericalMercator,transformation: function(){
  var t=0.5/(Math.PI*o.Projection.SphericalMercator.R);return new o.Transformation(t,0.5,-t,0.5);
 }()}),o.CRS.EPSG900913=o.extend({},o.CRS.EPSG3857,{code: "EPSG:900913"}),o.CRS.EPSG4326=o.extend({},o.CRS.Earth,{code: "EPSG:4326",projection: o.Projection.LonLat,transformation: new o.Transformation(1/180,1,-1/180,0.5)}),o.Map=o.Evented.extend({options: {crs: o.CRS.EPSG3857,fadeAnimation: !0,trackResize: !0,markerZoomAnimation: !0},initialize: function(t,e){
  e=o.setOptions(this,e),this._initContainer(t),this._initLayout(),this._onResize=o.bind(this._onResize,this),this._initEvents(),e.maxBounds&&this.setMaxBounds(e.maxBounds),e.zoom!==i&&(this._zoom=this._limitZoom(e.zoom)),e.center&&e.zoom!==i&&this.setView(o.latLng(e.center),e.zoom,{reset: !0}),this._handlers=[],this._layers={},this._zoomBoundLayers={},this._sizeChanged=!0,this.callInitHooks(),this._addLayers(this.options.layers);
 },setView: function(t,e){
  return (e=e===i?this.getZoom():e, this._resetView(o.latLng(t),this._limitZoom(e)), this);
 },setZoom: function(t,e){
  return this._loaded?this.setView(this.getCenter(),t,{zoom: e}):(this._zoom=this._limitZoom(t),this);
 },zoomIn: function(t,e){
  return this.setZoom(this._zoom+(t||1),e);
 },zoomOut: function(t,e){
  return this.setZoom(this._zoom-(t||1),e);
 },setZoomAround: function(t,e,i){
  var n=this.getZoomScale(e),s=this.getSize().divideBy(2),a=t instanceof o.Point?t:this.latLngToContainerPoint(t),r=a.subtract(s).multiplyBy(1-1/n),h=this.containerPointToLatLng(s.add(r));return this.setView(h,e,{zoom: i});
 },fitBounds: function(t,e){
  e=e||{},t=t.getBounds?t.getBounds():o.latLngBounds(t);var i=o.point(e.paddingTopLeft||e.padding||[0,0]),n=o.point(e.paddingBottomRight||e.padding||[0,0]),s=this.getBoundsZoom(t,!1,i.add(n));s=e.maxZoom?Math.min(e.maxZoom,s):s;var a=n.subtract(i).divideBy(2),r=this.project(t.getSouthWest(),s),h=this.project(t.getNorthEast(),s),l=this.unproject(r.add(h).divideBy(2).add(a),s);return this.setView(l,s,e);
 },fitWorld: function(t){
  return this.fitBounds([[-90,-180],[90,180]],t);
 },panTo: function(t,e){
  return this.setView(t,this._zoom,{pan: e});
 },panBy: function(t){
  return (this.fire("movestart"), this._rawPanBy(o.point(t)), this.fire("move"), this.fire("moveend"));
 },setMaxBounds: function(t){
  return (t=o.latLngBounds(t), this.options.maxBounds=t, t?(this._loaded&&this._panInsideMaxBounds(),this.on("moveend",this._panInsideMaxBounds)):this.off("moveend",this._panInsideMaxBounds));
 },panInsideBounds: function(t,e){
  var i=this.getCenter(),n=this._limitCenter(i,this._zoom,t);return i.equals(n)?this:this.panTo(n,e);
 },invalidateSize: function(t){
  if(!this._loaded)return this;t=o.extend({animate: !1,pan: !0},t===!0?{animate: !0}:t);var e=this.getSize();this._sizeChanged=!0,this._initialCenter=null;var i=this.getSize(),n=e.divideBy(2).round(),s=i.divideBy(2).round(),a=n.subtract(s);return a.x||a.y?(t.animate&&t.pan?this.panBy(a):(t.pan&&this._rawPanBy(a),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(o.bind(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize: e,newSize: i})):this;
 },stop: function(){
  return (o.Util.cancelAnimFrame(this._flyToFrame), this._panAnim&&this._panAnim.stop(), this);
 },addHandler: function(t,e){
  if(!e)return this;var i=this[t]=new e(this);return (this._handlers.push(i), this.options[t]&&i.enable(), this);
 },remove: function(){
  this._initEvents("off");try{
   delete this._container._leaflet;
  }catch(t){
   this._container._leaflet=i;
  }return (o.DomUtil.remove(this._mapPane), this._clearControlPos&&this._clearControlPos(), this._clearHandlers(), this._loaded&&this.fire("unload"), this);
 },createPane: function(t,e){
  var i="leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),n=o.DomUtil.create("div",i,e||this._mapPane);return (t&&(this._panes[t]=n), n);
 },getCenter: function(){
  return (this._checkIfLoaded(), this._initialCenter&&!this._moved()?this._initialCenter:this.layerPointToLatLng(this._getCenterLayerPoint()));
 },getZoom: function(){
  return this._zoom;
 },getBounds: function(){
  var t=this.getPixelBounds(),e=this.unproject(t.getBottomLeft()),i=this.unproject(t.getTopRight());return new o.LatLngBounds(e,i);
 },getMinZoom: function(){
  return this.options.minZoom===i?this._layersMinZoom||0:this.options.minZoom;
 },getMaxZoom: function(){
  return this.options.maxZoom===i?this._layersMaxZoom===i?1/0:this._layersMaxZoom:this.options.maxZoom;
 },getBoundsZoom: function(t,e,i){
  t=o.latLngBounds(t);var n,s=this.getMinZoom()-(e?1:0),a=this.getMaxZoom(),r=this.getSize(),h=t.getNorthWest(),l=t.getSouthEast(),u=!0;i=o.point(i||[0,0]);do s++,n=this.project(l,s).subtract(this.project(h,s)).add(i).floor(),u=e?n.x<r.x||n.y<r.y:r.contains(n);while(u&&a>=s);return u&&e?null:e?s:s-1;
 },getSize: function(){
  return((!this._size||this._sizeChanged)&&(this._size=new o.Point(this._container.clientWidth,this._container.clientHeight),this._sizeChanged=!1), this._size.clone());
 },getPixelBounds: function(t,e){
  var i=this._getTopLeftPoint(t,e);return new o.Bounds(i,i.add(this.getSize()));
 },getPixelOrigin: function(){
  return (this._checkIfLoaded(), this._pixelOrigin);
 },getPixelWorldBounds: function(t){
  return this.options.crs.getProjectedBounds(t===i?this.getZoom():t);
 },getPane: function(t){
  return"string"==typeof t?this._panes[t]:t;
 },getPanes: function(){
  return this._panes;
 },getContainer: function(){
  return this._container;
 },getZoomScale: function(t,e){
  var n=this.options.crs;return (e=e===i?this._zoom:e, n.scale(t)/n.scale(e));
 },getScaleZoom: function(t,e){
  return (e=e===i?this._zoom:e, e+Math.log(t)/Math.LN2);
 },project: function(t,e){
  return (e=e===i?this._zoom:e, this.options.crs.latLngToPoint(o.latLng(t),e));
 },unproject: function(t,e){
  return (e=e===i?this._zoom:e, this.options.crs.pointToLatLng(o.point(t),e));
 },layerPointToLatLng: function(t){
  var e=o.point(t).add(this.getPixelOrigin());return this.unproject(e);
 },latLngToLayerPoint: function(t){
  var e=this.project(o.latLng(t))._round();return e._subtract(this.getPixelOrigin());
 },wrapLatLng: function(t){
  return this.options.crs.wrapLatLng(o.latLng(t));
 },distance: function(t,e){
  return this.options.crs.distance(o.latLng(t),o.latLng(e));
 },containerPointToLayerPoint: function(t){
  return o.point(t).subtract(this._getMapPanePos());
 },layerPointToContainerPoint: function(t){
  return o.point(t).add(this._getMapPanePos());
 },containerPointToLatLng: function(t){
  var e=this.containerPointToLayerPoint(o.point(t));return this.layerPointToLatLng(e);
 },latLngToContainerPoint: function(t){
  return this.layerPointToContainerPoint(this.latLngToLayerPoint(o.latLng(t)));
 },mouseEventToContainerPoint: function(t){
  return o.DomEvent.getMousePosition(t,this._container);
 },mouseEventToLayerPoint: function(t){
  return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t));
 },mouseEventToLatLng: function(t){
  return this.layerPointToLatLng(this.mouseEventToLayerPoint(t));
 },_initContainer: function(t){
  var e=this._container=o.DomUtil.get(t);if(!e)throw new Error("Map container not found.");if(e._leaflet)throw new Error("Map container is already initialized.");e._leaflet=!0;
 },_initLayout: function(){
  var t=this._container;this._fadeAnimated=this.options.fadeAnimation&&o.Browser.any3d,o.DomUtil.addClass(t,"leaflet-container"+(o.Browser.touch?" leaflet-touch":"")+(o.Browser.retina?" leaflet-retina":"")+(o.Browser.ielt9?" leaflet-oldie":"")+(o.Browser.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":""));var e=o.DomUtil.getStyle(t,"position");"absolute"!==e&&"relative"!==e&&"fixed"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos();
 },_initPanes: function(){
  var t=this._panes={};this._mapPane=this.createPane("mapPane",this._container),this.createPane("tilePane"),this.createPane("shadowPane"),this.createPane("overlayPane"),this.createPane("markerPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(o.DomUtil.addClass(t.markerPane,"leaflet-zoom-hide"),o.DomUtil.addClass(t.shadowPane,"leaflet-zoom-hide"));
 },_resetView: function(t,e,i,n){
  var s=this._zoom!==e;n||(this.fire("movestart"),s&&this.fire("zoomstart")),this._zoom=e,this._initialCenter=t,i||o.DomUtil.setPosition(this._mapPane,new o.Point(0,0)),this._pixelOrigin=this._getNewPixelOrigin(t);var a=!this._loaded;this._loaded=!0,this.fire("viewreset",{hard: !i}),a&&this.fire("load"),this.fire("move"),(s||n)&&this.fire("zoomend"),this.fire("moveend",{hard: !i});
 },_rawPanBy: function(t){
  o.DomUtil.setPosition(this._mapPane,this._getMapPanePos().subtract(t));
 },_getZoomSpan: function(){
  return this.getMaxZoom()-this.getMinZoom();
 },_panInsideMaxBounds: function(){
  this.panInsideBounds(this.options.maxBounds);
 },_checkIfLoaded: function(){
  if(!this._loaded)throw new Error("Set map center and zoom first.");
 },_initEvents: function(e){
  o.DomEvent&&(e=e||"on",o.DomEvent[e](this._container,"click dblclick mousedown mouseup mouseenter mouseleave mousemove contextmenu",this._handleMouseEvent,this),this.options.trackResize&&o.DomEvent[e](t,"resize",this._onResize,this));
 },_onResize: function(){
  o.Util.cancelAnimFrame(this._resizeRequest),this._resizeRequest=o.Util.requestAnimFrame(function(){
   this.invalidateSize({debounceMoveend: !0});
  },this,!1,this._container);
 },_handleMouseEvent: function(t){
  this._loaded&&this._fireMouseEvent(this,t,"mouseenter"===t.type?"mouseover":"mouseleave"===t.type?"mouseout":t.type);
 },_fireMouseEvent: function(t,e,i,n,s){
  if(i=i||e.type,!o.DomEvent._skipped(e)){
   if("click"===i){
    var a=t.options.draggable===!0?t:this;if(!e._simulated&&(a.dragging&&a.dragging.moved()||this.boxZoom&&this.boxZoom.moved()))return void o.DomEvent.stopPropagation(e);t.fire("preclick");
   }if(t.listens(i,n)){
    "contextmenu"===i&&o.DomEvent.preventDefault(e),("click"===i||"dblclick"===i||"contextmenu"===i)&&o.DomEvent.stopPropagation(e);var r={originalEvent: e,containerPoint: this.mouseEventToContainerPoint(e)};r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=s||this.layerPointToLatLng(r.layerPoint),t.fire(i,r,n);
   }
  }
 },_clearHandlers: function(){
  for(var t=0,e=this._handlers.length;e>t;t++)this._handlers[t].disable();
 },whenReady: function(t,e){
  return (this._loaded?t.call(e||this,{target: this}):this.on("load",t,e), this);
 },_getMapPanePos: function(){
  return o.DomUtil.getPosition(this._mapPane)||new o.Point(0,0);
 },_moved: function(){
  var t=this._getMapPanePos();return t&&!t.equals([0,0]);
 },_getTopLeftPoint: function(t,e){
  var n=t&&e!==i?this._getNewPixelOrigin(t,e):this.getPixelOrigin();return n.subtract(this._getMapPanePos());
 },_getNewPixelOrigin: function(t,e){
  var i=this.getSize()._divideBy(2);return this.project(t,e)._subtract(i)._add(this._getMapPanePos())._round();
 },_latLngToNewLayerPoint: function(t,e,i){
  var n=this._getNewPixelOrigin(i,e);return this.project(t,e)._subtract(n);
 },_getCenterLayerPoint: function(){
  return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
 },_getCenterOffset: function(t){
  return this.latLngToLayerPoint(t).subtract(this._getCenterLayerPoint());
 },_limitCenter: function(t,e,i){
  if(!i)return t;var n=this.project(t,e),s=this.getSize().divideBy(2),a=new o.Bounds(n.subtract(s),n.add(s)),r=this._getBoundsOffset(a,i,e);return this.unproject(n.add(r),e);
 },_limitOffset: function(t,e){
  if(!e)return t;var i=this.getPixelBounds(),n=new o.Bounds(i.min.add(t),i.max.add(t));return t.add(this._getBoundsOffset(n,e));
 },_getBoundsOffset: function(t,e,i){
  var n=this.project(e.getNorthWest(),i).subtract(t.min),s=this.project(e.getSouthEast(),i).subtract(t.max),a=this._rebound(n.x,-s.x),r=this._rebound(n.y,-s.y);return new o.Point(a,r);
 },_rebound: function(t,e){
  return t+e>0?Math.round(t-e)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(e));
 },_limitZoom: function(t){
  var e=this.getMinZoom(),i=this.getMaxZoom();return Math.max(e,Math.min(i,t));
 }}),o.map=function(t,e){
  return new o.Map(t,e);
 },o.Layer=o.Evented.extend({options: {pane: "overlayPane"},addTo: function(t){
  return (t.addLayer(this), this);
 },remove: function(){
  return this.removeFrom(this._map||this._mapToAdd);
 },removeFrom: function(t){
  return (t&&t.removeLayer(this), this);
 },getPane: function(t){
  return this._map.getPane(t?this.options[t]||t:this.options.pane);
 },_layerAdd: function(t){
  var e=t.target;e.hasLayer(this)&&(this._map=e,this._zoomAnimated=e._zoomAnimated,this.onAdd(e),this.getAttribution&&this._map.attributionControl&&this._map.attributionControl.addAttribution(this.getAttribution()),this.getEvents&&e.on(this.getEvents(),this),this.fire("add"),e.fire("layeradd",{layer: this}));
 }}),o.Map.include({addLayer: function(t){
  var e=o.stamp(t);return this._layers[e]?t:(this._layers[e]=t,t._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t),this);
 },removeLayer: function(t){
  var e=o.stamp(t);return this._layers[e]?(this._loaded&&t.onRemove(this),t.getAttribution&&this.attributionControl&&this.attributionControl.removeAttribution(t.getAttribution()),t.getEvents&&this.off(t.getEvents(),t),delete this._layers[e],this._loaded&&(this.fire("layerremove",{layer: t}),t.fire("remove")),t._map=t._mapToAdd=null,this):this;
 },hasLayer: function(t){
  return!!t&&o.stamp(t)in this._layers;
 },eachLayer: function(t,e){
  for(var i in this._layers)t.call(e,this._layers[i]);return this;
 },_addLayers: function(t){
  t=t?o.Util.isArray(t)?t:[t]:[];for(var e=0,i=t.length;i>e;e++)this.addLayer(t[e]);
 },_addZoomLimit: function(t){
  (isNaN(t.options.maxZoom)||!isNaN(t.options.minZoom))&&(this._zoomBoundLayers[o.stamp(t)]=t,this._updateZoomLevels());
 },_removeZoomLimit: function(t){
  var e=o.stamp(t);this._zoomBoundLayers[e]&&(delete this._zoomBoundLayers[e],this._updateZoomLevels());
 },_updateZoomLevels: function(){
  var t=1/0,e=-1/0,n=this._getZoomSpan();for(var o in this._zoomBoundLayers){
   var s=this._zoomBoundLayers[o].options;t=s.minZoom===i?t:Math.min(t,s.minZoom),e=s.maxZoom===i?e:Math.max(e,s.maxZoom);
  }this._layersMaxZoom=e===-1/0?i:e,this._layersMinZoom=1/0===t?i:t,n!==this._getZoomSpan()&&this.fire("zoomlevelschange");
 }}),o.Projection.Mercator={R: 6378137,R_MINOR: 6356752.314245179,bounds: o.bounds([-20037508.34279,-15496570.73972],[20037508.34279,18764656.23138]),project: function(t){
  var e=Math.PI/180,i=this.R,n=t.lat*e,s=this.R_MINOR/i,a=Math.sqrt(1-s*s),r=a*Math.sin(n),h=Math.tan(Math.PI/4-n/2)/Math.pow((1-r)/(1+r),a/2);
  return (n=-i*Math.log(Math.max(h,1e-10)), new o.Point(t.lng*e*i,n));
 },unproject: function(t){
  for(var e,i=180/Math.PI,n=this.R,s=this.R_MINOR/n,a=Math.sqrt(1-s*s),r=Math.exp(-t.y/n),h=Math.PI/2-2*Math.atan(r),l=0,u=0.1;15>l&&Math.abs(u)>1e-7;l++)e=a*Math.sin(h),e=Math.pow((1-e)/(1+e),a/2),u=Math.PI/2-2*Math.atan(r*e)-h,h+=u;return new o.LatLng(h*i,t.x*i/n);
 }},o.CRS.EPSG3395=o.extend({},o.CRS.Earth,{code: "EPSG:3395",projection: o.Projection.Mercator,transformation: function(){
  var t=0.5/(Math.PI*o.Projection.Mercator.R);return new o.Transformation(t,0.5,-t,0.5);
 }()}),o.GridLayer=o.Layer.extend({options: {pane: "tilePane",tileSize: 256,opacity: 1,updateWhenIdle: o.Browser.mobile,updateInterval: 200,attribution: null,zIndex: null,bounds: null,minZoom: 0},initialize: function(t){
  t=o.setOptions(this,t);
 },onAdd: function(){
  this._initContainer(),this._levels={},this._tiles={},this._viewReset(),this._update();
 },beforeAdd: function(t){
  t._addZoomLimit(this);
 },onRemove: function(t){
  o.DomUtil.remove(this._container),t._removeZoomLimit(this),this._container=null,this._tileZoom=null;
 },bringToFront: function(){
  return (this._map&&(o.DomUtil.toFront(this._container),this._setAutoZIndex(Math.max)), this);
 },bringToBack: function(){
  return (this._map&&(o.DomUtil.toBack(this._container),this._setAutoZIndex(Math.min)), this);
 },getAttribution: function(){
  return this.options.attribution;
 },getContainer: function(){
  return this._container;
 },setOpacity: function(t){
  return (this.options.opacity=t, this._map&&this._updateOpacity(), this);
 },setZIndex: function(t){
  return (this.options.zIndex=t, this._updateZIndex(), this);
 },redraw: function(){
  return (this._map&&(this._removeAllTiles(),this._update()), this);
 },getEvents: function(){
  var t={viewreset: this._viewReset,moveend: this._move};return (this.options.updateWhenIdle||(t.move=o.Util.throttle(this._move,this.options.updateInterval,this)), this._zoomAnimated&&(t.zoomanim=this._animateZoom), t);
 },createTile: function(){
  return e.createElement("div");
 },_updateZIndex: function(){
  this._container&&this.options.zIndex!==i&&null!==this.options.zIndex&&(this._container.style.zIndex=this.options.zIndex);
 },_setAutoZIndex: function(t){
  for(var e,i=this.getPane().children,n=-t(-1/0,1/0),o=0,s=i.length;s>o;o++)e=i[o].style.zIndex,i[o]!==this._container&&e&&(n=t(n,+e));isFinite(n)&&(this.options.zIndex=n+t(-1,1),this._updateZIndex());
 },_updateOpacity: function(){
  var t=this.options.opacity;if(!o.Browser.ielt9&&!this._map._fadeAnimated)return void o.DomUtil.setOpacity(this._container,t);var e=+new Date,i=!1;for(var n in this._tiles){
   var s=this._tiles[n];if(s.current&&s.loaded&&!s.active){
    var a=Math.min(1,(e-s.loaded)/200);1>a?(o.DomUtil.setOpacity(s.el,t*a),i=!0):(o.DomUtil.setOpacity(s.el,t),s.active=!0,this._pruneTiles());
   }
  }i&&(o.Util.cancelAnimFrame(this._fadeFrame),this._fadeFrame=o.Util.requestAnimFrame(this._updateOpacity,this));
 },_initContainer: function(){
  this._container||(this._container=o.DomUtil.create("div","leaflet-layer"),this._updateZIndex(),this.options.opacity<1&&this._updateOpacity(),this.getPane().appendChild(this._container));
 },_updateLevels: function(){
  var t=this._tileZoom,e=this.options.maxZoom;for(var i in this._levels)this._levels[i].el.children.length||i===t?this._levels[i].el.style.zIndex=e-Math.abs(t-i):(o.DomUtil.remove(this._levels[i].el),delete this._levels[i]);var n=this._levels[t],s=this._map;return (n||(n=this._levels[t]={},n.el=o.DomUtil.create("div","leaflet-tile-container leaflet-zoom-animated",this._container),n.el.style.zIndex=e,n.origin=s.project(s.unproject(s.getPixelOrigin()),t).round(),n.zoom=t,this._setZoomTransform(n,s.getCenter(),s.getZoom()),o.Util.falseFn(n.el.offsetWidth)), this._level=n, n);
 },_pruneTiles: function(){
  var t,e;for(t in this._tiles)e=this._tiles[t],e.retain=e.current;for(t in this._tiles)if(e=this._tiles[t],e.current&&!e.active){
   var i=e.coords;this._retainParent(i.x,i.y,i.z,i.z-5)||this._retainChildren(i.x,i.y,i.z,i.z+2);
  }for(t in this._tiles)this._tiles[t].retain||this._removeTile(t);
 },_removeAllTiles: function(){
  for(var t in this._tiles)this._removeTile(t);
 },_retainParent: function(t,e,i,n){
  var o=Math.floor(t/2),s=Math.floor(e/2),a=i-1,r=o+":"+s+":"+a,h=this._tiles[r];return h&&h.active?(h.retain=!0,!0):(h&&h.loaded&&(h.retain=!0),a>n?this._retainParent(o,s,a,n):!1);
 },_retainChildren: function(t,e,i,n){
  for(var o=2*t;2*t+2>o;o++)for(var s=2*e;2*e+2>s;s++){
   var a=o+":"+s+":"+(i+1),r=this._tiles[a];r&&r.active?r.retain=!0:(r&&r.loaded&&(r.retain=!0),n>i+1&&this._retainChildren(o,s,i+1,n));
  }
 },_viewReset: function(t){
  var e=this._map;this._reset(e.getCenter(),e.getZoom(),t&&t.hard);
 },_animateZoom: function(t){
  this._reset(t.center,t.zoom,!1,!0);
 },_reset: function(t,e,i,n){
  var o=Math.round(e),s=this._tileZoom!==o;(s||i)&&(this._abortLoading&&this._abortLoading(),this._tileZoom=o,this._updateLevels(),this._resetGrid(),this._update(t,o),n||this._pruneTiles()),this._setZoomTransforms(t,e);
 },_setZoomTransforms: function(t,e){
  for(var i in this._levels)this._setZoomTransform(this._levels[i],t,e);
 },_setZoomTransform: function(t,e,i){
  var n=this._map.getZoomScale(i,t.zoom),s=t.origin.multiplyBy(n).subtract(this._map._getNewPixelOrigin(e,i)).round();o.DomUtil.setTransform(t.el,s,n);
 },_resetGrid: function(){
  var t=this._map,e=t.options.crs,i=this._tileSize=this._getTileSize(),n=this._tileZoom,o=this._map.getPixelWorldBounds(this._tileZoom);o&&(this._globalTileRange=this._pxBoundsToTileRange(o)),this._wrapX=e.wrapLng&&[Math.floor(t.project([0,e.wrapLng[0]],n).x/i),Math.ceil(t.project([0,e.wrapLng[1]],n).x/i)],this._wrapY=e.wrapLat&&[Math.floor(t.project([e.wrapLat[0],0],n).y/i),Math.ceil(t.project([e.wrapLat[1],0],n).y/i)];
 },_getTileSize: function(){
  return this.options.tileSize;
 },_move: function(){
  this._update(),this._pruneTiles();
 },_update: function(t,n){
  var s=this._map;if(s){
   t===i&&(t=s.getCenter()),n===i&&(n=Math.round(s.getZoom()));var a=s.getPixelBounds(t,n),r=this._pxBoundsToTileRange(a),h=r.getCenter(),l=[];for(var u in this._tiles)this._tiles[u].current=!1;for(var c=r.min.y;c<=r.max.y;c++)for(var d=r.min.x;d<=r.max.x;d++){
    var m=new o.Point(d,c);if(m.z=n,this._isValidTile(m)){
     var _=this._tiles[this._tileCoordsToKey(m)];_?_.current=!0:l.push(m);
    }
   }if(l.sort(function(t,e){
    return t.distanceTo(h)-e.distanceTo(h);
   }),0!==l.length){
    this._noTilesToLoad()&&this.fire("loading");var p=e.createDocumentFragment();for(d=0;d<l.length;d++)this._addTile(l[d],p);this._level.el.appendChild(p);
   }
  }
 },_isValidTile: function(t){
  var e=this._map.options.crs;if(!e.infinite){
   var i=this._globalTileRange;if(!e.wrapLng&&(t.x<i.min.x||t.x>i.max.x)||!e.wrapLat&&(t.y<i.min.y||t.y>i.max.y))return!1;
  }if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return o.latLngBounds(this.options.bounds).intersects(n);
 },_keyToBounds: function(t){
  return this._tileCoordsToBounds(this._keyToTileCoords(t));
 },_tileCoordsToBounds: function(t){
  var e=this._map,i=this._getTileSize(),n=t.multiplyBy(i),s=n.add([i,i]),a=e.wrapLatLng(e.unproject(n,t.z)),r=e.wrapLatLng(e.unproject(s,t.z));return new o.LatLngBounds(a,r);
 },_tileCoordsToKey: function(t){
  return t.x+":"+t.y+":"+t.z;
 },_keyToTileCoords: function(t){
  var e=t.split(":"),i=new o.Point(+e[0],+e[1]);return (i.z=+e[2], i);
 },_removeTile: function(t){
  var e=this._tiles[t];e&&(o.DomUtil.remove(e.el),delete this._tiles[t],this.fire("tileunload",{tile: e.el,coords: this._keyToTileCoords(t)}));
 },_initTile: function(t){
  o.DomUtil.addClass(t,"leaflet-tile"),t.style.width=this._tileSize+"px",t.style.height=this._tileSize+"px",t.onselectstart=o.Util.falseFn,t.onmousemove=o.Util.falseFn,o.Browser.ielt9&&this.options.opacity<1&&o.DomUtil.setOpacity(t,this.options.opacity),o.Browser.android&&!o.Browser.android23&&(t.style.WebkitBackfaceVisibility="hidden");
 },_addTile: function(t,e){
  var i=this._getTilePos(t),n=this._tileCoordsToKey(t),s=this.createTile(this._wrapCoords(t),o.bind(this._tileReady,this,t));this._initTile(s),this.createTile.length<2&&setTimeout(o.bind(this._tileReady,this,t,null,s),0),o.DomUtil.setPosition(s,i,!0),this._tiles[n]={el: s,coords: t,current: !0},e.appendChild(s),this.fire("tileloadstart",{tile: s,coords: t});
 },_tileReady: function(t,e,i){
  e&&this.fire("tileerror",{error: e,tile: i,coords: t});var n=this._tileCoordsToKey(t);i=this._tiles[n],i&&(i.loaded=+new Date,this._map._fadeAnimated?(o.DomUtil.setOpacity(i.el,0),o.Util.cancelAnimFrame(this._fadeFrame),this._fadeFrame=o.Util.requestAnimFrame(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),o.DomUtil.addClass(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile: i.el,coords: t}),this._noTilesToLoad()&&this.fire("load"));
 },_getTilePos: function(t){
  return t.multiplyBy(this._tileSize).subtract(this._level.origin);
 },_wrapCoords: function(t){
  var e=new o.Point(this._wrapX?o.Util.wrapNum(t.x,this._wrapX):t.x,this._wrapY?o.Util.wrapNum(t.y,this._wrapY):t.y);return (e.z=t.z, e);
 },_pxBoundsToTileRange: function(t){
  return new o.Bounds(t.min.divideBy(this._tileSize).floor(),t.max.divideBy(this._tileSize).ceil().subtract([1,1]));
 },_noTilesToLoad: function(){
  for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0;
 }}),o.gridLayer=function(t){
  return new o.GridLayer(t);
 },o.TileLayer=o.GridLayer.extend({options: {maxZoom: 18,subdomains: "abc",errorTileUrl: "",zoomOffset: 0,maxNativeZoom: null,tms: !1,zoomReverse: !1,detectRetina: !1,crossOrigin: !1},initialize: function(t,e){
  this._url=t,e=o.setOptions(this,e),e.detectRetina&&o.Browser.retina&&e.maxZoom>0&&(e.tileSize=Math.floor(e.tileSize/2),e.zoomOffset++,e.minZoom=Math.max(0,e.minZoom),e.maxZoom--),"string"==typeof e.subdomains&&(e.subdomains=e.subdomains.split("")),o.Browser.android||this.on("tileunload",this._onTileRemove);
 },setUrl: function(t,e){
  return (this._url=t, e||this.redraw(), this);
 },createTile: function(t,i){
  var n=e.createElement("img");return (n.onload=o.bind(this._tileOnLoad,this,i,n), n.onerror=o.bind(this._tileOnError,this,i,n), this.options.crossOrigin&&(n.crossOrigin=""), n.alt="", n.src=this.getTileUrl(t), n);
 },getTileUrl: function(t){
  return o.Util.template(this._url,o.extend({r: this.options.detectRetina&&o.Browser.retina&&this.options.maxZoom>0?"@2x":"",s: this._getSubdomain(t),x: t.x,y: this.options.tms?this._globalTileRange.max.y-t.y:t.y,z: this._getZoomForUrl()},this.options));
 },_tileOnLoad: function(t,e){
  t(null,e);
 },_tileOnError: function(t,e,i){
  var n=this.options.errorTileUrl;n&&(e.src=n),t(i,e);
 },_getTileSize: function(){
  var t=this._map,e=this.options,i=t.getZoom()+e.zoomOffset,n=e.maxNativeZoom;return null!==n&&i>n?Math.round(t.getZoomScale(n,i)*e.tileSize):e.tileSize;
 },_onTileRemove: function(t){
  t.tile.onload=null;
 },_getZoomForUrl: function(){
  var t=this.options,e=this._tileZoom;return (t.zoomReverse&&(e=t.maxZoom-e), e+=t.zoomOffset, t.maxNativeZoom?Math.min(e,t.maxNativeZoom):e);
 },_getSubdomain: function(t){
  var e=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[e];
 },_abortLoading: function(){
  var t,e;for(t in this._tiles)e=this._tiles[t].el,e.onload=o.Util.falseFn,e.onerror=o.Util.falseFn,e.complete||(e.src=o.Util.emptyImageUrl,o.DomUtil.remove(e));
 }}),o.tileLayer=function(t,e){
  return new o.TileLayer(t,e);
 },o.Icon=o.Class.extend({initialize: function(t){
  o.setOptions(this,t);
 },createIcon: function(t){
  return this._createIcon("icon",t);
 },createShadow: function(t){
  return this._createIcon("shadow",t);
 },_createIcon: function(t,e){
  var i=this._getIconUrl(t);if(!i){
   if("icon"===t)throw new Error("iconUrl not set in Icon options (see the docs).");return null;
  }var n=this._createImg(i,e&&"IMG"===e.tagName?e:null);return (this._setIconStyles(n,t), n);
 },_setIconStyles: function(t,e){
  var i=this.options,n=o.point(i[e+"Size"]),s=o.point("shadow"===e&&i.shadowAnchor||i.iconAnchor||n&&n.divideBy(2,!0));t.className="leaflet-marker-"+e+" "+(i.className||""),s&&(t.style.marginLeft=-s.x+"px",t.style.marginTop=-s.y+"px"),n&&(t.style.width=n.x+"px",t.style.height=n.y+"px");
 },_createImg: function(t,i){
  return (i=i||e.createElement("img"), i.src=t, i);
 },_getIconUrl: function(t){
  return o.Browser.retina&&this.options[t+"RetinaUrl"]||this.options[t+"Url"];
 }}),o.icon=function(t){
  return new o.Icon(t);
 },o.Icon.Default=o.Icon.extend({options: {iconSize: [25,41],iconAnchor: [12,41],popupAnchor: [1,-34],shadowSize: [41,41]},_getIconUrl: function(t){
  var e=t+"Url";if(this.options[e])return this.options[e];var i=o.Icon.Default.imagePath||"https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/images/";if(!i)throw new Error("Couldn't autodetect L.Icon.Default.imagePath, set it manually.");return i+"/marker-"+t+(o.Browser.retina&&"icon"===t?"-2x":"")+".png";
 }}),o.Icon.Default.imagePath=function(){
  var t,i,n,o,s=e.getElementsByTagName("script"),a=/[\/^]leaflet[\-\._]?([\w\-\._]*)\.js\??/;for(t=0,i=s.length;i>t;t++)if(n=s[t].src,n.match(a))return (o=n.split(a)[0], (o?o+"/":"")+"images");
 }(),o.Marker=o.Layer.extend({options: {pane: "markerPane",icon: new o.Icon.Default,interactive: !0,keyboard: !0,zIndexOffset: 0,opacity: 1,riseOffset: 250},initialize: function(t,e){
  o.setOptions(this,e),this._latlng=o.latLng(t);
 },onAdd: function(t){
  this._zoomAnimated=this._zoomAnimated&&t.options.markerZoomAnimation,this._initIcon(),this.update();
 },onRemove: function(){
  this.dragging&&this.dragging.enabled()&&this.dragging.removeHooks(),this._removeIcon(),this._removeShadow();
 },getEvents: function(){
  var t={viewreset: this.update};return (this._zoomAnimated&&(t.zoomanim=this._animateZoom), t);
 },getLatLng: function(){
  return this._latlng;
 },setLatLng: function(t){
  var e=this._latlng;return (this._latlng=o.latLng(t), this.update(), this.fire("move",{oldLatLng: e,latlng: this._latlng}));
 },setZIndexOffset: function(t){
  return (this.options.zIndexOffset=t, this.update());
 },setIcon: function(t){
  return (this.options.icon=t, this._map&&(this._initIcon(),this.update()), this._popup&&this.bindPopup(this._popup,this._popup.options), this);
 },update: function(){
  if(this._icon){
   var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t);
  }return this;
 },_initIcon: function(){
  var t=this.options,e="leaflet-zoom-"+(this._zoomAnimated?"animated":"hide"),i=t.icon.createIcon(this._icon),n=!1;i!==this._icon&&(this._icon&&this._removeIcon(),n=!0,t.title&&(i.title=t.title),t.alt&&(i.alt=t.alt)),o.DomUtil.addClass(i,e),t.keyboard&&(i.tabIndex="0"),this._icon=i,this._initInteraction(),o.DomEvent&&t.riseOnHover&&o.DomEvent.on(i,{mouseover: this._bringToFront,mouseout: this._resetZIndex},this);var s=t.icon.createShadow(this._shadow),a=!1;s!==this._shadow&&(this._removeShadow(),a=!0),s&&o.DomUtil.addClass(s,e),this._shadow=s,t.opacity<1&&this._updateOpacity(),n&&this.getPane().appendChild(this._icon),s&&a&&this.getPane("shadowPane").appendChild(this._shadow);
 },_removeIcon: function(){
  o.DomEvent&&this.options.riseOnHover&&o.DomEvent.off(this._icon,{mouseover: this._bringToFront,mouseout: this._resetZIndex},this),o.DomUtil.remove(this._icon),this._icon=null;
 },_removeShadow: function(){
  this._shadow&&o.DomUtil.remove(this._shadow),this._shadow=null;
 },_setPos: function(t){
  o.DomUtil.setPosition(this._icon,t),this._shadow&&o.DomUtil.setPosition(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex();
 },_updateZIndex: function(t){
  this._icon.style.zIndex=this._zIndex+t;
 },_animateZoom: function(t){
  var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center).round();this._setPos(e);
 },_initInteraction: function(){
  if(this.options.interactive&&(o.DomUtil.addClass(this._icon,"leaflet-interactive"),o.DomEvent&&o.DomEvent.on(this._icon,"click dblclick mousedown mouseup mouseover mousemove mouseout contextmenu keypress",this._fireMouseEvent,this),o.Handler.MarkerDrag)){
   var t=this.options.draggable;this.dragging&&(t=this.dragging.enabled(),this.dragging.disable()),this.dragging=new o.Handler.MarkerDrag(this),t&&this.dragging.enable();
  }
 },_fireMouseEvent: function(t,e){
  "mousedown"===t.type&&o.DomEvent.preventDefault(t),"keypress"===t.type&&13===t.keyCode&&(e="click"),this._map&&this._map._fireMouseEvent(this,t,e,!0,this._latlng);
 },setOpacity: function(t){
  return (this.options.opacity=t, this._map&&this._updateOpacity(), this);
 },_updateOpacity: function(){
  var t=this.options.opacity;o.DomUtil.setOpacity(this._icon,t),this._shadow&&o.DomUtil.setOpacity(this._shadow,t);
 },_bringToFront: function(){
  this._updateZIndex(this.options.riseOffset);
 },_resetZIndex: function(){
  this._updateZIndex(0);
 }}),o.marker=function(t,e){
  return new o.Marker(t,e);
 },o.Map.mergeOptions({closePopupOnClick: !0}),o.Popup=o.Layer.extend({options: {pane: "popupPane",minWidth: 50,maxWidth: 300,offset: [0,7],autoPan: !0,autoPanPadding: [5,5],closeButton: !0,autoClose: !0,zoomAnimation: !0},initialize: function(t,e){
  o.setOptions(this,t),this._source=e;
 },onAdd: function(t){
  this._zoomAnimated=this._zoomAnimated&&this.options.zoomAnimation,this._container||this._initLayout(),t._fadeAnimated&&o.DomUtil.setOpacity(this._container,0),clearTimeout(this._removeTimeout),this.getPane().appendChild(this._container),this.update(),t._fadeAnimated&&o.DomUtil.setOpacity(this._container,1),t.fire("popupopen",{popup: this}),this._source&&this._source.fire("popupopen",{popup: this},!0);
 },openOn: function(t){
  return (t.openPopup(this), this);
 },onRemove: function(t){
  t._fadeAnimated?(o.DomUtil.setOpacity(this._container,0),this._removeTimeout=setTimeout(o.bind(o.DomUtil.remove,o.DomUtil,this._container),200)):o.DomUtil.remove(this._container),t.fire("popupclose",{popup: this}),this._source&&this._source.fire("popupclose",{popup: this},!0);
 },getLatLng: function(){
  return this._latlng;
 },setLatLng: function(t){
  return (this._latlng=o.latLng(t), this._map&&(this._updatePosition(),this._adjustPan()), this);
 },getContent: function(){
  return this._content;
 },setContent: function(t){
  return (this._content=t, this.update(), this);
 },update: function(){
  this._map&&(this._container.style.visibility="hidden",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility="",this._adjustPan());
 },getEvents: function(){
  var t={viewreset: this._updatePosition},e=this.options;return (this._zoomAnimated&&(t.zoomanim=this._animateZoom), ("closeOnClick"in e?e.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this._close), e.keepInView&&(t.moveend=this._adjustPan), t);
 },isOpen: function(){
  return!!this._map&&this._map.hasLayer(this);
 },_close: function(){
  this._map&&this._map.closePopup(this);
 },_initLayout: function(){
  var t="leaflet-popup",e=this._container=o.DomUtil.create("div",t+" "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide"));if(this.options.closeButton){
   var i=this._closeButton=o.DomUtil.create("a",t+"-close-button",e);i.href="#close",i.innerHTML="&#215;",o.DomEvent.on(i,"click",this._onCloseButtonClick,this);
  }var n=this._wrapper=o.DomUtil.create("div",t+"-content-wrapper",e);this._contentNode=o.DomUtil.create("div",t+"-content",n),o.DomEvent.disableClickPropagation(n).disableScrollPropagation(this._contentNode).on(n,"contextmenu",o.DomEvent.stopPropagation),this._tipContainer=o.DomUtil.create("div",t+"-tip-container",e),this._tip=o.DomUtil.create("div",t+"-tip",this._tipContainer);
 },_updateContent: function(){
  if(this._content){
   var t=this._contentNode;if("string"==typeof this._content)t.innerHTML=this._content;else{
    for(;t.hasChildNodes();)t.removeChild(t.firstChild);t.appendChild(this._content);
   }this.fire("contentupdate");
  }
 },_updateLayout: function(){
  var t=this._contentNode,e=t.style;e.width="",e.whiteSpace="nowrap";var i=t.offsetWidth;i=Math.min(i,this.options.maxWidth),i=Math.max(i,this.options.minWidth),e.width=i+1+"px",e.whiteSpace="",e.height="";var n=t.offsetHeight,s=this.options.maxHeight,a="leaflet-popup-scrolled";s&&n>s?(e.height=s+"px",o.DomUtil.addClass(t,a)):o.DomUtil.removeClass(t,a),this._containerWidth=this._container.offsetWidth;
 },_updatePosition: function(){
  if(this._map){
   var t=this._map.latLngToLayerPoint(this._latlng),e=o.point(this.options.offset);this._zoomAnimated?o.DomUtil.setPosition(this._container,t):e=e.add(t);var i=this._containerBottom=-e.y,n=this._containerLeft=-Math.round(this._containerWidth/2)+e.x;this._container.style.bottom=i+"px",this._container.style.left=n+"px";
  }
 },_animateZoom: function(t){
  var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);o.DomUtil.setPosition(this._container,e);
 },_adjustPan: function(){
  if(this.options.autoPan){
   var t=this._map,e=this._container.offsetHeight,i=this._containerWidth,n=new o.Point(this._containerLeft,-e-this._containerBottom);this._zoomAnimated&&n._add(o.DomUtil.getPosition(this._container));var s=t.layerPointToContainerPoint(n),a=o.point(this.options.autoPanPadding),r=o.point(this.options.autoPanPaddingTopLeft||a),h=o.point(this.options.autoPanPaddingBottomRight||a),l=t.getSize(),u=0,c=0;s.x+i+h.x>l.x&&(u=s.x+i-l.x+h.x),s.x-u-r.x<0&&(u=s.x-r.x),s.y+e+h.y>l.y&&(c=s.y+e-l.y+h.y),s.y-c-r.y<0&&(c=s.y-r.y),(u||c)&&t.fire("autopanstart").panBy([u,c]);
  }
 },_onCloseButtonClick: function(t){
  this._close(),o.DomEvent.stop(t);
 }}),o.popup=function(t,e){
  return new o.Popup(t,e);
 },o.Map.include({openPopup: function(t,e,i){
  if(!(t instanceof o.Popup)){
   var n=t;t=new o.Popup(i).setContent(n);
  }return (e&&t.setLatLng(e), this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t)));
 },closePopup: function(t){
  return (t&&t!==this._popup||(t=this._popup,this._popup=null), t&&this.removeLayer(t), this);
 }}),o.Layer.include({bindPopup: function(t,e){
  return (t instanceof o.Popup?(this._popup=t,t._source=this):((!this._popup||e)&&(this._popup=new o.Popup(e,this)),this._popup.setContent(t)), this._popupHandlersAdded||(this.on({click: this._openPopup,remove: this.closePopup,move: this._movePopup}),this._popupHandlersAdded=!0), this);
 },unbindPopup: function(){
  return (this._popup&&(this.off({click: this._openPopup,remove: this.closePopup,move: this._movePopup}),this._popupHandlersAdded=!1,this._popup=null), this);
 },openPopup: function(t){
  return (this._popup&&this._map&&this._map.openPopup(this._popup,t||this._latlng||this.getCenter()), this);
 },closePopup: function(){
  return (this._popup&&this._popup._close(), this);
 },togglePopup: function(){
  return (this._popup&&(this._popup._map?this.closePopup():this.openPopup()), this);
 },setPopupContent: function(t){
  return (this._popup&&this._popup.setContent(t), this);
 },getPopup: function(){
  return this._popup;
 },_openPopup: function(t){
  this._map.openPopup(this._popup,t.latlng);
 },_movePopup: function(t){
  this._popup.setLatLng(t.latlng);
 }}),o.Marker.include({bindPopup: function(t,e){
  var i=o.point(this.options.icon.options.popupAnchor||[0,0]).add(o.Popup.prototype.options.offset);return (e=o.extend({offset: i},e), o.Layer.prototype.bindPopup.call(this,t,e));
 },_openPopup: o.Layer.prototype.togglePopup}),o.LayerGroup=o.Layer.extend({initialize: function(t){
  this._layers={};var e,i;if(t)for(e=0,i=t.length;i>e;e++)this.addLayer(t[e]);
 },addLayer: function(t){
  var e=this.getLayerId(t);return (this._layers[e]=t, this._map&&this._map.addLayer(t), this);
 },removeLayer: function(t){
  var e=t in this._layers?t:this.getLayerId(t);return (this._map&&this._layers[e]&&this._map.removeLayer(this._layers[e]), delete this._layers[e], this);
 },hasLayer: function(t){
  return!!t&&(t in this._layers||this.getLayerId(t)in this._layers);
 },clearLayers: function(){
  for(var t in this._layers)this.removeLayer(this._layers[t]);return this;
 },invoke: function(t){
  var e,i,n=Array.prototype.slice.call(arguments,1);for(e in this._layers)i=this._layers[e],i[t]&&i[t].apply(i,n);return this;
 },onAdd: function(t){
  for(var e in this._layers)t.addLayer(this._layers[e]);
 },onRemove: function(t){
  for(var e in this._layers)t.removeLayer(this._layers[e]);
 },eachLayer: function(t,e){
  for(var i in this._layers)t.call(e,this._layers[i]);return this;
 },getLayer: function(t){
  return this._layers[t];
 },getLayers: function(){
  var t=[];for(var e in this._layers)t.push(this._layers[e]);return t;
 },setZIndex: function(t){
  return this.invoke("setZIndex",t);
 },getLayerId: function(t){
  return o.stamp(t);
 }}),o.layerGroup=function(t){
  return new o.LayerGroup(t);
 },o.FeatureGroup=o.LayerGroup.extend({addLayer: function(t){
  return this.hasLayer(t)?this:(t.addEventParent(this),o.LayerGroup.prototype.addLayer.call(this,t),this._popupContent&&t.bindPopup&&t.bindPopup(this._popupContent,this._popupOptions),this.fire("layeradd",{layer: t}));
 },removeLayer: function(t){
  return this.hasLayer(t)?(t in this._layers&&(t=this._layers[t]),t.removeEventParent(this),o.LayerGroup.prototype.removeLayer.call(this,t),this._popupContent&&this.invoke("unbindPopup"),this.fire("layerremove",{layer: t})):this;
 },bindPopup: function(t,e){
  return (this._popupContent=t, this._popupOptions=e, this.invoke("bindPopup",t,e));
 },openPopup: function(t){
  for(var e in this._layers){
   this._layers[e].openPopup(t);break;
  }return this;
 },setStyle: function(t){
  return this.invoke("setStyle",t);
 },bringToFront: function(){
  return this.invoke("bringToFront");
 },bringToBack: function(){
  return this.invoke("bringToBack");
 },getBounds: function(){
  var t=new o.LatLngBounds;return (this.eachLayer(function(e){
   t.extend(e.getBounds?e.getBounds():e.getLatLng());
  }), t);
 }}),o.featureGroup=function(t){
  return new o.FeatureGroup(t);
 };var a="_leaflet_events";o.DomEvent={on: function(t,e,i,n){
  if("object"==typeof e)for(var s in e)this._on(t,s,e[s],i);else{
   e=o.Util.splitWords(e);for(var a=0,r=e.length;r>a;a++)this._on(t,e[a],i,n);
  }return this;
 },off: function(t,e,i,n){
  if("object"==typeof e)for(var s in e)this._off(t,s,e[s],i);else{
   e=o.Util.splitWords(e);for(var a=0,r=e.length;r>a;a++)this._off(t,e[a],i,n);
  }return this;
 },_on: function(e,i,n,s){
  var r=i+o.stamp(n)+(s?"_"+o.stamp(s):"");if(e[a]&&e[a][r])return this;var h=function(i){
   return n.call(s||e,i||t.event);
  },l=h;return (o.Browser.pointer&&0===i.indexOf("touch")?this.addPointerListener(e,i,h,r):o.Browser.touch&&"dblclick"===i&&this.addDoubleTapListener?this.addDoubleTapListener(e,h,r):"addEventListener"in e?"mousewheel"===i?(e.addEventListener("DOMMouseScroll",h,!1),e.addEventListener(i,h,!1)):"mouseenter"===i||"mouseleave"===i?(h=function(i){
   i=i||t.event,o.DomEvent._checkMouse(e,i)&&l(i);
  },e.addEventListener("mouseenter"===i?"mouseover":"mouseout",h,!1)):("click"===i&&o.Browser.android&&(h=function(t){
   return o.DomEvent._filterClick(t,l);
  }),e.addEventListener(i,h,!1)):"attachEvent"in e&&e.attachEvent("on"+i,h), e[a]=e[a]||{}, e[a][r]=h, this);
 },_off: function(t,e,i,n){
  var s=e+o.stamp(i)+(n?"_"+o.stamp(n):""),r=t[a]&&t[a][s];return r?(o.Browser.pointer&&0===e.indexOf("touch")?this.removePointerListener(t,e,s):o.Browser.touch&&"dblclick"===e&&this.removeDoubleTapListener?this.removeDoubleTapListener(t,s):"removeEventListener"in t?"mousewheel"===e?(t.removeEventListener("DOMMouseScroll",r,!1),t.removeEventListener(e,r,!1)):t.removeEventListener("mouseenter"===e?"mouseover":"mouseleave"===e?"mouseout":e,r,!1):"detachEvent"in t&&t.detachEvent("on"+e,r),t[a][s]=null,this):this;
 },stopPropagation: function(t){
  return (t.stopPropagation?t.stopPropagation():t.cancelBubble=!0, o.DomEvent._skipped(t), this);
 },disableScrollPropagation: function(t){
  return o.DomEvent.on(t,"mousewheel MozMousePixelScroll",o.DomEvent.stopPropagation);
 },disableClickPropagation: function(t){
  var e=o.DomEvent.stopPropagation;return (o.DomEvent.on(t,o.Draggable.START.join(" "),e), o.DomEvent.on(t,{click: o.DomEvent._fakeStop,dblclick: e}));
 },preventDefault: function(t){
  return (t.preventDefault?t.preventDefault():t.returnValue=!1, this);
 },stop: function(t){
  return o.DomEvent.preventDefault(t).stopPropagation(t);
 },getMousePosition: function(t,e){
  if(!e)return new o.Point(t.clientX,t.clientY);var i=e.getBoundingClientRect();return new o.Point(t.clientX-i.left-e.clientLeft,t.clientY-i.top-e.clientTop);
 },getWheelDelta: function(t){
  var e=0;return (t.wheelDelta&&(e=t.wheelDelta/120), t.detail&&(e=-t.detail/3), e);
 },_skipEvents: {},_fakeStop: function(t){
  o.DomEvent._skipEvents[t.type]=!0;
 },_skipped: function(t){
  var e=this._skipEvents[t.type];return (this._skipEvents[t.type]=!1, e);
 },_checkMouse: function(t,e){
  var i=e.relatedTarget;if(!i)return!0;try{
   for(;i&&i!==t;)i=i.parentNode;
  }catch(n){
   return!1;
  }return i!==t;
 },_filterClick: function(t,e){
  var i=t.timeStamp||t.originalEvent.timeStamp,n=o.DomEvent._lastClick&&i-o.DomEvent._lastClick;return n&&n>100&&500>n||t.target._simulatedClick&&!t._simulated?void o.DomEvent.stop(t):(o.DomEvent._lastClick=i,void e(t));
 }},o.DomEvent.addListener=o.DomEvent.on,o.DomEvent.removeListener=o.DomEvent.off,o.Draggable=o.Evented.extend({statics: {START: o.Browser.touch?["touchstart","mousedown"]:["mousedown"],END: {mousedown: "mouseup",touchstart: "touchend",pointerdown: "touchend",MSPointerDown: "touchend"},MOVE: {mousedown: "mousemove",touchstart: "touchmove",pointerdown: "touchmove",MSPointerDown: "touchmove"}},initialize: function(t,e){
  this._element=t,this._dragStartTarget=e||t;
 },enable: function(){
  this._enabled||(o.DomEvent.on(this._dragStartTarget,o.Draggable.START.join(" "),this._onDown,this),this._enabled=!0);
 },disable: function(){
  this._enabled&&(o.DomEvent.off(this._dragStartTarget,o.Draggable.START.join(" "),this._onDown,this),this._enabled=!1,this._moved=!1);
 },_onDown: function(t){
  if(this._moved=!1,!(t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||(o.DomEvent.stopPropagation(t),o.DomUtil.hasClass(this._element,"leaflet-zoom-anim")||(o.DomUtil.disableImageDrag(),o.DomUtil.disableTextSelection(),this._moving)))){
   this.fire("down");var i=t.touches?t.touches[0]:t;this._startPoint=new o.Point(i.clientX,i.clientY),this._startPos=this._newPos=o.DomUtil.getPosition(this._element),o.DomEvent.on(e,o.Draggable.MOVE[t.type],this._onMove,this).on(e,o.Draggable.END[t.type],this._onUp,this);
  }
 },_onMove: function(t){
  if(t.touches&&t.touches.length>1)return void(this._moved=!0);var i=t.touches&&1===t.touches.length?t.touches[0]:t,n=new o.Point(i.clientX,i.clientY),s=n.subtract(this._startPoint);(s.x||s.y)&&(o.Browser.touch&&Math.abs(s.x)+Math.abs(s.y)<3||(o.DomEvent.preventDefault(t),this._moved||(this.fire("dragstart"),this._moved=!0,this._startPos=o.DomUtil.getPosition(this._element).subtract(s),o.DomUtil.addClass(e.body,"leaflet-dragging"),this._lastTarget=t.target||t.srcElement,o.DomUtil.addClass(this._lastTarget,"leaflet-drag-target")),this._newPos=this._startPos.add(s),this._moving=!0,o.Util.cancelAnimFrame(this._animRequest),this._animRequest=o.Util.requestAnimFrame(this._updatePosition,this,!0,this._dragStartTarget)));
 },_updatePosition: function(){
  this.fire("predrag"),o.DomUtil.setPosition(this._element,this._newPos),this.fire("drag");
 },_onUp: function(){
  o.DomUtil.removeClass(e.body,"leaflet-dragging"),this._lastTarget&&(o.DomUtil.removeClass(this._lastTarget,"leaflet-drag-target"),this._lastTarget=null);for(var t in o.Draggable.MOVE)o.DomEvent.off(e,o.Draggable.MOVE[t],this._onMove,this).off(e,o.Draggable.END[t],this._onUp,this);o.DomUtil.enableImageDrag(),o.DomUtil.enableTextSelection(),this._moved&&this._moving&&(o.Util.cancelAnimFrame(this._animRequest),this.fire("dragend",{distance: this._newPos.distanceTo(this._startPos)})),this._moving=!1;
 }}),o.Handler=o.Class.extend({initialize: function(t){
  this._map=t;
 },enable: function(){
  this._enabled||(this._enabled=!0,this.addHooks());
 },disable: function(){
  this._enabled&&(this._enabled=!1,this.removeHooks());
 },enabled: function(){
  return!!this._enabled;
 }}),o.Map.mergeOptions({dragging: !0,inertia: !o.Browser.android23,inertiaDeceleration: 3400,inertiaMaxSpeed: 1/0,easeLinearity: 0.2,worldCopyJump: !1}),o.Map.Drag=o.Handler.extend({addHooks: function(){
  if(!this._draggable){
   var t=this._map;this._draggable=new o.Draggable(t._mapPane,t._container),this._draggable.on({down: this._onDown,dragstart: this._onDragStart,drag: this._onDrag,dragend: this._onDragEnd},this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDrag,this),t.on("viewreset",this._onViewReset,this),t.whenReady(this._onViewReset,this));
  }this._draggable.enable();
 },removeHooks: function(){
  this._draggable.disable();
 },moved: function(){
  return this._draggable&&this._draggable._moved;
 },_onDown: function(){
  this._map.stop();
 },_onDragStart: function(){
  var t=this._map;t.fire("movestart").fire("dragstart"),t.options.inertia&&(this._positions=[],this._times=[]);
 },_onDrag: function(){
  if(this._map.options.inertia){
   var t=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos;this._positions.push(e),this._times.push(t),t-this._times[0]>50&&(this._positions.shift(),this._times.shift());
  }this._map.fire("move").fire("drag");
 },_onViewReset: function(){
  var t=this._map.getSize().divideBy(2),e=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=e.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x;
 },_onPreDrag: function(){
  var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,s=(n+e+i)%t-e-i,a=Math.abs(o+i)<Math.abs(s+i)?o:s;
  this._draggable._absPos=this._draggable._newPos.clone(),this._draggable._newPos.x=a;
 },_onDragEnd: function(t){
  var e=this._map,i=e.options,n=!i.inertia||this._times.length<2;if(e.fire("dragend",t),n)e.fire("moveend");else{
   var s=this._lastPos.subtract(this._positions[0]),a=(this._lastTime-this._times[0])/1000,r=i.easeLinearity,h=s.multiplyBy(r/a),l=h.distanceTo([0,0]),u=Math.min(i.inertiaMaxSpeed,l),c=h.multiplyBy(u/l),d=u/(i.inertiaDeceleration*r),m=c.multiplyBy(-d/2).round();m.x&&m.y?(m=e._limitOffset(m,e.options.maxBounds),o.Util.requestAnimFrame(function(){
    e.panBy(m,{duration: d,easeLinearity: r,noMoveStart: !0,animate: !0});
   })):e.fire("moveend");
  }
 }}),o.Map.addInitHook("addHandler","dragging",o.Map.Drag),o.Map.mergeOptions({doubleClickZoom: !0}),o.Map.DoubleClickZoom=o.Handler.extend({addHooks: function(){
  this._map.on("dblclick",this._onDoubleClick,this);
 },removeHooks: function(){
  this._map.off("dblclick",this._onDoubleClick,this);
 },_onDoubleClick: function(t){
  var e=this._map,i=e.getZoom(),n=t.originalEvent.shiftKey?Math.ceil(i)-1:Math.floor(i)+1;"center"===e.options.doubleClickZoom?e.setZoom(n):e.setZoomAround(t.containerPoint,n);
 }}),o.Map.addInitHook("addHandler","doubleClickZoom",o.Map.DoubleClickZoom),o.Map.mergeOptions({scrollWheelZoom: !0,wheelDebounceTime: 40}),o.Map.ScrollWheelZoom=o.Handler.extend({addHooks: function(){
  o.DomEvent.on(this._map._container,{mousewheel: this._onWheelScroll,MozMousePixelScroll: o.DomEvent.preventDefault},this),this._delta=0;
 },removeHooks: function(){
  o.DomEvent.off(this._map._container,{mousewheel: this._onWheelScroll,MozMousePixelScroll: o.DomEvent.preventDefault},this);
 },_onWheelScroll: function(t){
  var e=o.DomEvent.getWheelDelta(t),i=this._map.options.wheelDebounceTime;this._delta+=e,this._lastMousePos=this._map.mouseEventToContainerPoint(t),this._startTime||(this._startTime=+new Date);var n=Math.max(i-(+new Date-this._startTime),0);clearTimeout(this._timer),this._timer=setTimeout(o.bind(this._performZoom,this),n),o.DomEvent.stop(t);
 },_performZoom: function(){
  var t=this._map,e=this._delta,i=t.getZoom();t.stop(),e=e>0?Math.ceil(e):Math.floor(e),e=Math.max(Math.min(e,4),-4),e=t._limitZoom(i+e)-i,this._delta=0,this._startTime=null,e&&("center"===t.options.scrollWheelZoom?t.setZoom(i+e):t.setZoomAround(this._lastMousePos,i+e));
 }}),o.Map.addInitHook("addHandler","scrollWheelZoom",o.Map.ScrollWheelZoom),o.extend(o.DomEvent,{_touchstart: o.Browser.msPointer?"MSPointerDown":o.Browser.pointer?"pointerdown":"touchstart",_touchend: o.Browser.msPointer?"MSPointerUp":o.Browser.pointer?"pointerup":"touchend",addDoubleTapListener: function(t,e,i){
  function n(t){
   var e;if(e=o.Browser.pointer?o.DomEvent._pointersCount:t.touches.length,!(e>1)){
    var i=Date.now(),n=i-(a||i);r=t.touches?t.touches[0]:t,h=n>0&&l>=n,a=i;
   }
  }function s(){
   if(h){
    if(o.Browser.pointer){
     var t,i,n={};for(i in r)t=r[i],n[i]=t&&t.bind?t.bind(r):t;r=n;
    }r.type="dblclick",e(r),a=null;
   }
  }var a,r,h=!1,l=250,u="_leaflet_",c=this._touchstart,d=this._touchend;return (t[u+c+i]=n, t[u+d+i]=s, t.addEventListener(c,n,!1), t.addEventListener(d,s,!1), this);
 },removeDoubleTapListener: function(t,e){
  var i="_leaflet_",n=t[i+this._touchend+e];return (t.removeEventListener(this._touchstart,t[i+this._touchstart+e],!1), t.removeEventListener(this._touchend,n,!1), this);
 }}),o.extend(o.DomEvent,{POINTER_DOWN: o.Browser.msPointer?"MSPointerDown":"pointerdown",POINTER_MOVE: o.Browser.msPointer?"MSPointerMove":"pointermove",POINTER_UP: o.Browser.msPointer?"MSPointerUp":"pointerup",POINTER_CANCEL: o.Browser.msPointer?"MSPointerCancel":"pointercancel",_pointers: {},_pointersCount: 0,addPointerListener: function(t,e,i,n){
  return("touchstart"===e?this._addPointerStart(t,i,n):"touchmove"===e?this._addPointerMove(t,i,n):"touchend"===e&&this._addPointerEnd(t,i,n), this);
 },removePointerListener: function(t,e,i){
  var n=t["_leaflet_"+e+i];return("touchstart"===e?t.removeEventListener(this.POINTER_DOWN,n,!1):"touchmove"===e?t.removeEventListener(this.POINTER_MOVE,n,!1):"touchend"===e&&(t.removeEventListener(this.POINTER_UP,n,!1),t.removeEventListener(this.POINTER_CANCEL,n,!1)), this);
 },_addPointerStart: function(t,i,n){
  var s=o.bind(function(t){
   o.DomEvent.preventDefault(t),this._handlePointer(t,i);
  },this);if(t["_leaflet_touchstart"+n]=s,t.addEventListener(this.POINTER_DOWN,s,!1),!this._pointerDocListener){
   var a=o.bind(this._globalPointerUp,this);e.documentElement.addEventListener(this.POINTER_DOWN,o.bind(this._globalPointerDown,this),!0),e.documentElement.addEventListener(this.POINTER_MOVE,o.bind(this._globalPointerMove,this),!0),e.documentElement.addEventListener(this.POINTER_UP,a,!0),e.documentElement.addEventListener(this.POINTER_CANCEL,a,!0),this._pointerDocListener=!0;
  }
 },_globalPointerDown: function(t){
  this._pointers[t.pointerId]=t,this._pointersCount++;
 },_globalPointerMove: function(t){
  this._pointers[t.pointerId]&&(this._pointers[t.pointerId]=t);
 },_globalPointerUp: function(t){
  delete this._pointers[t.pointerId],this._pointersCount--;
 },_handlePointer: function(t,e){
  t.touches=[];for(var i in this._pointers)t.touches.push(this._pointers[i]);t.changedTouches=[t],e(t);
 },_addPointerMove: function(t,e,i){
  var n=o.bind(function(t){
   (t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&"mouse"!==t.pointerType||0!==t.buttons)&&this._handlePointer(t,e);
  },this);t["_leaflet_touchmove"+i]=n,t.addEventListener(this.POINTER_MOVE,n,!1);
 },_addPointerEnd: function(t,e,i){
  var n=o.bind(function(t){
   this._handlePointer(t,e);
  },this);t["_leaflet_touchend"+i]=n,t.addEventListener(this.POINTER_UP,n,!1),t.addEventListener(this.POINTER_CANCEL,n,!1);
 }}),o.Map.mergeOptions({touchZoom: o.Browser.touch&&!o.Browser.android23,bounceAtZoomLimits: !0}),o.Map.TouchZoom=o.Handler.extend({addHooks: function(){
  o.DomEvent.on(this._map._container,"touchstart",this._onTouchStart,this);
 },removeHooks: function(){
  o.DomEvent.off(this._map._container,"touchstart",this._onTouchStart,this);
 },_onTouchStart: function(t){
  var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){
   var n=i.mouseEventToLayerPoint(t.touches[0]),s=i.mouseEventToLayerPoint(t.touches[1]),a=i._getCenterLayerPoint();this._startCenter=n.add(s)._divideBy(2),this._startDist=n.distanceTo(s),this._moved=!1,this._zooming=!0,this._centerOffset=a.subtract(this._startCenter),i.stop(),o.DomEvent.on(e,"touchmove",this._onTouchMove,this).on(e,"touchend",this._onTouchEnd,this),o.DomEvent.preventDefault(t);
  }
 },_onTouchMove: function(t){
  if(t.touches&&2===t.touches.length&&this._zooming){
   var e=this._map,i=e.mouseEventToLayerPoint(t.touches[0]),n=e.mouseEventToLayerPoint(t.touches[1]);if(this._scale=i.distanceTo(n)/this._startDist,this._delta=i._add(n)._divideBy(2)._subtract(this._startCenter),!e.options.bounceAtZoomLimits){
    var s=e.getScaleZoom(this._scale);if(s<=e.getMinZoom()&&this._scale<1||s>=e.getMaxZoom()&&this._scale>1)return;
   }this._moved||(e.fire("movestart").fire("zoomstart"),this._moved=!0),o.Util.cancelAnimFrame(this._animRequest),this._animRequest=o.Util.requestAnimFrame(this._updateOnMove,this,!0,this._map._container),o.DomEvent.preventDefault(t);
  }
 },_updateOnMove: function(){
  var t=this._map;this._center="center"===t.options.touchZoom?t.getCenter():t.layerPointToLatLng(this._getTargetCenter()),this._zoom=t.getScaleZoom(this._scale),t._animateZoom(this._center,this._zoom);
 },_onTouchEnd: function(){
  if(!this._moved||!this._zooming)return void(this._zooming=!1);this._zooming=!1,o.Util.cancelAnimFrame(this._animRequest),o.DomEvent.off(e,"touchmove",this._onTouchMove).off(e,"touchend",this._onTouchEnd);var t=this._map,i=t.getZoom(),n=this._zoom-i,s=t._limitZoom(n>0?Math.ceil(this._zoom):Math.floor(this._zoom));t._animateZoom(this._center,s,!0);
 },_getTargetCenter: function(){
  var t=this._centerOffset.subtract(this._delta).divideBy(this._scale);return this._startCenter.add(t);
 }}),o.Map.addInitHook("addHandler","touchZoom",o.Map.TouchZoom),o.Map.mergeOptions({tap: !0,tapTolerance: 15}),o.Map.Tap=o.Handler.extend({addHooks: function(){
  o.DomEvent.on(this._map._container,"touchstart",this._onDown,this);
 },removeHooks: function(){
  o.DomEvent.off(this._map._container,"touchstart",this._onDown,this);
 },_onDown: function(t){
  if(t.touches){
   if(o.DomEvent.preventDefault(t),this._fireClick=!0,t.touches.length>1)return (this._fireClick=!1, void clearTimeout(this._holdTimeout));var i=t.touches[0],n=i.target;this._startPos=this._newPos=new o.Point(i.clientX,i.clientY),n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.addClass(n,"leaflet-active"),this._holdTimeout=setTimeout(o.bind(function(){
    this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i));
   },this),1000),this._simulateEvent("mousedown",i),o.DomEvent.on(e,{touchmove: this._onMove,touchend: this._onUp},this);
  }
 },_onUp: function(t){
  if(clearTimeout(this._holdTimeout),o.DomEvent.off(e,{touchmove: this._onMove,touchend: this._onUp},this),this._fireClick&&t&&t.changedTouches){
   var i=t.changedTouches[0],n=i.target;n&&n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.removeClass(n,"leaflet-active"),this._simulateEvent("mouseup",i),this._isTapValid()&&this._simulateEvent("click",i);
  }
 },_isTapValid: function(){
  return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance;
 },_onMove: function(t){
  var e=t.touches[0];this._newPos=new o.Point(e.clientX,e.clientY);
 },_simulateEvent: function(i,n){
  var o=e.createEvent("MouseEvents");o._simulated=!0,n.target._simulatedClick=!0,o.initMouseEvent(i,!0,!0,t,1,n.screenX,n.screenY,n.clientX,n.clientY,!1,!1,!1,!1,0,null),n.target.dispatchEvent(o);
 }}),o.Browser.touch&&!o.Browser.pointer&&o.Map.addInitHook("addHandler","tap",o.Map.Tap),o.Map.mergeOptions({boxZoom: !0}),o.Map.BoxZoom=o.Handler.extend({initialize: function(t){
  this._map=t,this._container=t._container,this._pane=t._panes.overlayPane;
 },addHooks: function(){
  o.DomEvent.on(this._container,"mousedown",this._onMouseDown,this);
 },removeHooks: function(){
  o.DomEvent.off(this._container,"mousedown",this._onMouseDown,this);
 },moved: function(){
  return this._moved;
 },_onMouseDown: function(t){
  return!t.shiftKey||1!==t.which&&1!==t.button?!1:(this._moved=!1,o.DomUtil.disableTextSelection(),o.DomUtil.disableImageDrag(),this._startPoint=this._map.mouseEventToContainerPoint(t),void o.DomEvent.on(e,{contextmenu: o.DomEvent.stop,mousemove: this._onMouseMove,mouseup: this._onMouseUp,keydown: this._onKeyDown},this));
 },_onMouseMove: function(t){
  this._moved||(this._moved=!0,this._box=o.DomUtil.create("div","leaflet-zoom-box",this._container),o.DomUtil.addClass(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var e=new o.Bounds(this._point,this._startPoint),i=e.getSize();o.DomUtil.setPosition(this._box,e.min),this._box.style.width=i.x+"px",this._box.style.height=i.y+"px";
 },_finish: function(){
  this._moved&&(o.DomUtil.remove(this._box),o.DomUtil.removeClass(this._container,"leaflet-crosshair")),o.DomUtil.enableTextSelection(),o.DomUtil.enableImageDrag(),o.DomEvent.off(e,{contextmenu: o.DomEvent.stop,mousemove: this._onMouseMove,mouseup: this._onMouseUp,keydown: this._onKeyDown},this);
 },_onMouseUp: function(t){
  if((1===t.which||1===t.button)&&(this._finish(),this._moved)){
   var e=new o.LatLngBounds(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(e).fire("boxzoomend",{boxZoomBounds: e});
  }
 },_onKeyDown: function(t){
  27===t.keyCode&&this._finish();
 }}),o.Map.addInitHook("addHandler","boxZoom",o.Map.BoxZoom),o.Map.mergeOptions({keyboard: !0,keyboardPanOffset: 80,keyboardZoomOffset: 1}),o.Map.Keyboard=o.Handler.extend({keyCodes: {left: [37],right: [39],down: [40],up: [38],zoomIn: [187,107,61,171],zoomOut: [189,109,173]},initialize: function(t){
  this._map=t,this._setPanOffset(t.options.keyboardPanOffset),this._setZoomOffset(t.options.keyboardZoomOffset);
 },addHooks: function(){
  var t=this._map._container;-1===t.tabIndex&&(t.tabIndex="0"),o.DomEvent.on(t,{focus: this._onFocus,blur: this._onBlur,mousedown: this._onMouseDown},this),this._map.on({focus: this._addHooks,blur: this._removeHooks},this);
 },removeHooks: function(){
  this._removeHooks(),o.DomEvent.off(this._map._container,{focus: this._onFocus,blur: this._onBlur,mousedown: this._onMouseDown},this),this._map.off({focus: this._addHooks,blur: this._removeHooks},this);
 },_onMouseDown: function(){
  if(!this._focused){
   var i=e.body,n=e.documentElement,o=i.scrollTop||n.scrollTop,s=i.scrollLeft||n.scrollLeft;this._map._container.focus(),t.scrollTo(s,o);
  }
 },_onFocus: function(){
  this._focused=!0,this._map.fire("focus");
 },_onBlur: function(){
  this._focused=!1,this._map.fire("blur");
 },_setPanOffset: function(t){
  var e,i,n=this._panKeys={},o=this.keyCodes;for(e=0,i=o.left.length;i>e;e++)n[o.left[e]]=[-1*t,0];for(e=0,i=o.right.length;i>e;e++)n[o.right[e]]=[t,0];for(e=0,i=o.down.length;i>e;e++)n[o.down[e]]=[0,t];for(e=0,i=o.up.length;i>e;e++)n[o.up[e]]=[0,-1*t];
 },_setZoomOffset: function(t){
  var e,i,n=this._zoomKeys={},o=this.keyCodes;for(e=0,i=o.zoomIn.length;i>e;e++)n[o.zoomIn[e]]=t;for(e=0,i=o.zoomOut.length;i>e;e++)n[o.zoomOut[e]]=-t;
 },_addHooks: function(){
  o.DomEvent.on(e,"keydown",this._onKeyDown,this);
 },_removeHooks: function(){
  o.DomEvent.off(e,"keydown",this._onKeyDown,this);
 },_onKeyDown: function(t){
  if(!(t.altKey||t.ctrlKey||t.metaKey)){
   var e=t.keyCode,i=this._map;if(e in this._panKeys){
    if(i._panAnim&&i._panAnim._inProgress)return;i.panBy(this._panKeys[e]),i.options.maxBounds&&i.panInsideBounds(i.options.maxBounds);
   }else if(e in this._zoomKeys)i.setZoom(i.getZoom()+(t.shiftKey?3:1)*this._zoomKeys[e]);else{
    if(27!==e)return;i.closePopup();
   }o.DomEvent.stop(t);
  }
 }}),o.Map.addInitHook("addHandler","keyboard",o.Map.Keyboard),o.Handler.MarkerDrag=o.Handler.extend({initialize: function(t){
  this._marker=t;
 },addHooks: function(){
  var t=this._marker._icon;this._draggable||(this._draggable=new o.Draggable(t,t)),this._draggable.on({dragstart: this._onDragStart,drag: this._onDrag,dragend: this._onDragEnd},this).enable(),o.DomUtil.addClass(t,"leaflet-marker-draggable");
 },removeHooks: function(){
  this._draggable.off({dragstart: this._onDragStart,drag: this._onDrag,dragend: this._onDragEnd},this).disable(),this._marker._icon&&o.DomUtil.removeClass(this._marker._icon,"leaflet-marker-draggable");
 },moved: function(){
  return this._draggable&&this._draggable._moved;
 },_onDragStart: function(){
  this._marker.closePopup().fire("movestart").fire("dragstart");
 },_onDrag: function(){
  var t=this._marker,e=t._shadow,i=o.DomUtil.getPosition(t._icon),n=t._map.layerPointToLatLng(i);e&&o.DomUtil.setPosition(e,i),t._latlng=n,t.fire("move",{latlng: n}).fire("drag");
 },_onDragEnd: function(t){
  this._marker.fire("moveend").fire("dragend",t);
 }}),o.Control=o.Class.extend({options: {position: "topright"},initialize: function(t){
  o.setOptions(this,t);
 },getPosition: function(){
  return this.options.position;
 },setPosition: function(t){
  var e=this._map;return (e&&e.removeControl(this), this.options.position=t, e&&e.addControl(this), this);
 },getContainer: function(){
  return this._container;
 },addTo: function(t){
  this.remove(),this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),n=t._controlCorners[i];return (o.DomUtil.addClass(e,"leaflet-control"), -1!==i.indexOf("bottom")?n.insertBefore(e,n.firstChild):n.appendChild(e), this);
 },remove: function(){
  return this._map?(o.DomUtil.remove(this._container),this.onRemove&&this.onRemove(this._map),this._map=null,this):this;
 },_refocusOnMap: function(){
  this._map&&this._map.getContainer().focus();
 }}),o.control=function(t){
  return new o.Control(t);
 },o.Map.include({addControl: function(t){
  return (t.addTo(this), this);
 },removeControl: function(t){
  return (t.remove(), this);
 },_initControlPos: function(){
  function t(t,s){
   var a=i+t+" "+i+s;e[t+s]=o.DomUtil.create("div",a,n);
  }var e=this._controlCorners={},i="leaflet-",n=this._controlContainer=o.DomUtil.create("div",i+"control-container",this._container);t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right");
 },_clearControlPos: function(){
  o.DomUtil.remove(this._controlContainer);
 }}),o.Control.Zoom=o.Control.extend({options: {position: "topleft",zoomInText: "+",zoomInTitle: "Zoom in",zoomOutText: "-",zoomOutTitle: "Zoom out"},onAdd: function(t){
  var e="leaflet-control-zoom",i=o.DomUtil.create("div",e+" leaflet-bar"),n=this.options;return (this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn), this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut), this._updateDisabled(), t.on("zoomend zoomlevelschange",this._updateDisabled,this), i);
 },onRemove: function(t){
  t.off("zoomend zoomlevelschange",this._updateDisabled,this);
 },disable: function(){
  return (this._disabled=!0, this._updateDisabled(), this);
 },enable: function(){
  return (this._disabled=!1, this._updateDisabled(), this);
 },_zoomIn: function(t){
  this._disabled||this._map.zoomIn(t.shiftKey?3:1);
 },_zoomOut: function(t){
  this._disabled||this._map.zoomOut(t.shiftKey?3:1);
 },_createButton: function(t,e,i,n,s){
  var a=o.DomUtil.create("a",i,n);return (a.innerHTML=t, a.href="#", a.title=e, o.DomEvent.on(a,"mousedown dblclick",o.DomEvent.stopPropagation).on(a,"click",o.DomEvent.stop).on(a,"click",s,this).on(a,"click",this._refocusOnMap,this), a);
 },_updateDisabled: function(){
  var t=this._map,e="leaflet-disabled";o.DomUtil.removeClass(this._zoomInButton,e),o.DomUtil.removeClass(this._zoomOutButton,e),(this._disabled||t._zoom===t.getMinZoom())&&o.DomUtil.addClass(this._zoomOutButton,e),(this._disabled||t._zoom===t.getMaxZoom())&&o.DomUtil.addClass(this._zoomInButton,e);
 }}),o.Map.mergeOptions({zoomControl: !0}),o.Map.addInitHook(function(){
  this.options.zoomControl&&(this.zoomControl=new o.Control.Zoom,this.addControl(this.zoomControl));
 }),o.control.zoom=function(t){
  return new o.Control.Zoom(t);
 },o.Control.Attribution=o.Control.extend({options: {position: "bottomright",prefix: "<a href=\"https://leafletjs.com\" title=\"A JS library for interactive maps\">Leaflet</a>"},initialize: function(t){
  o.setOptions(this,t),this._attributions={}
 },onAdd: function(t){
  this._container=o.DomUtil.create("div","leaflet-control-attribution"),o.DomEvent&&o.DomEvent.disableClickPropagation(this._container);for(var e in t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return (this._update(), this._container);
 },setPrefix: function(t){
  return (this.options.prefix=t, this._update(), this);
 },addAttribution: function(t){
  return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):this;
 },removeAttribution: function(t){
  return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):this;
 },_update: function(){
  if(this._map){
   var t=[];for(var e in this._attributions)this._attributions[e]&&t.push(e);var i=[];this.options.prefix&&i.push(this.options.prefix),t.length&&i.push(t.join(", ")),this._container.innerHTML=i.join(" | ");
  }
 }}),o.Map.mergeOptions({attributionControl: !0}),o.Map.addInitHook(function(){
  this.options.attributionControl&&(this.attributionControl=(new o.Control.Attribution).addTo(this));
 }),o.control.attribution=function(t){
  return new o.Control.Attribution(t);
 },o.Control.Scale=o.Control.extend({options: {position: "bottomleft",maxWidth: 100,metric: !0,imperial: !0},onAdd: function(t){
  var e="leaflet-control-scale",i=o.DomUtil.create("div",e),n=this.options;return (this._addScales(n,e+"-line",i), t.on(n.updateWhenIdle?"moveend":"move",this._update,this), t.whenReady(this._update,this), i);
 },onRemove: function(t){
  t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this);
 },_addScales: function(t,e,i){
  t.metric&&(this._mScale=o.DomUtil.create("div",e,i)),t.imperial&&(this._iScale=o.DomUtil.create("div",e,i));
 },_update: function(){
  var t=this._map,e=t.getSize().y/2,i=o.CRS.Earth.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(i);
 },_updateScales: function(t){
  this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t);
 },_updateMetric: function(t){
  var e=this._getRoundNum(t),i=1000>e?e+" m":e/1000+" km";this._updateScale(this._mScale,i,e/t);
 },_updateImperial: function(t){
  var e,i,n,o=3.2808399*t;o>5280?(e=o/5280,i=this._getRoundNum(e),this._updateScale(this._iScale,i+" mi",i/e)):(n=this._getRoundNum(o),this._updateScale(this._iScale,n+" ft",n/o));
 },_updateScale: function(t,e,i){
  t.style.width=Math.round(this.options.maxWidth*i)+"px",t.innerHTML=e;
 },_getRoundNum: function(t){
  var e=Math.pow(10,(Math.floor(t)+"").length-1),i=t/e;return (i=i>=10?10:i>=5?5:i>=3?3:i>=2?2:1, e*i);
 }}),o.control.scale=function(t){
  return new o.Control.Scale(t);
 },o.Control.Layers=o.Control.extend({options: {collapsed: !0,position: "topright",autoZIndex: !0,hideSingleBase: !1},initialize: function(t,e,i){
  o.setOptions(this,i),this._layers={},this._lastZIndex=0,this._handlingClick=!1;for(var n in t)this._addLayer(t[n],n);for(n in e)this._addLayer(e[n],n,!0);
 },onAdd: function(){
  return (this._initLayout(), this._update(), this._container);
 },addBaseLayer: function(t,e){
  return (this._addLayer(t,e), this._update());
 },addOverlay: function(t,e){
  return (this._addLayer(t,e,!0), this._update());
 },removeLayer: function(t){
  return (t.off("add remove",this._onLayerChange,this), delete this._layers[o.stamp(t)], this._update());
 },_initLayout: function(){
  var t="leaflet-control-layers",e=this._container=o.DomUtil.create("div",t);e.setAttribute("aria-haspopup",!0),o.Browser.touch?o.DomEvent.on(e,"click",o.DomEvent.stopPropagation):o.DomEvent.disableClickPropagation(e).disableScrollPropagation(e);var i=this._form=o.DomUtil.create("form",t+"-list");if(this.options.collapsed){
   o.Browser.android||o.DomEvent.on(e,{mouseenter: this._expand,mouseleave: this._collapse},this);var n=this._layersLink=o.DomUtil.create("a",t+"-toggle",e);n.href="#",n.title="Layers",o.Browser.touch?o.DomEvent.on(n,"click",o.DomEvent.stop).on(n,"click",this._expand,this):o.DomEvent.on(n,"focus",this._expand,this),o.DomEvent.on(i,"click",function(){
    setTimeout(o.bind(this._onInputClick,this),0);
   },this),this._map.on("click",this._collapse,this);
  }else this._expand();this._baseLayersList=o.DomUtil.create("div",t+"-base",i),this._separator=o.DomUtil.create("div",t+"-separator",i),this._overlaysList=o.DomUtil.create("div",t+"-overlays",i),e.appendChild(i);
 },_addLayer: function(t,e,i){
  t.on("add remove",this._onLayerChange,this);var n=o.stamp(t);this._layers[n]={layer: t,name: e,overlay: i},this.options.autoZIndex&&t.setZIndex&&(this._lastZIndex++,t.setZIndex(this._lastZIndex));
 },_update: function(){
  if(!this._container)return this;o.DomUtil.empty(this._baseLayersList),o.DomUtil.empty(this._overlaysList);var t,e,i,n,s=0;for(i in this._layers)n=this._layers[i],this._addItem(n),e=e||n.overlay,t=t||!n.overlay,s+=n.overlay?0:1;return (this.options.hideSingleBase&&(t=t&&s>1,this._baseLayersList.style.display=t?"":"none"), this._separator.style.display=e&&t?"":"none", this);
 },_onLayerChange: function(t){
  this._handlingClick||this._update();var e=this._layers[o.stamp(t.target)].overlay,i=e?"add"===t.type?"overlayadd":"overlayremove":"add"===t.type?"baselayerchange":null;i&&this._map.fire(i,t.target);
 },_createRadioElement: function(t,i){
  var n="<input type=\"radio\" class=\"leaflet-control-layers-selector\" name=\""+t+"\""+(i?" checked=\"checked\"":"")+"/>",o=e.createElement("div");return (o.innerHTML=n, o.firstChild);
 },_addItem: function(t){
  var i,n=e.createElement("label"),s=this._map.hasLayer(t.layer);t.overlay?(i=e.createElement("input"),i.type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=s):i=this._createRadioElement("leaflet-base-layers",s),i.layerId=o.stamp(t.layer),o.DomEvent.on(i,"click",this._onInputClick,this);var a=e.createElement("span");a.innerHTML=" "+t.name,n.appendChild(i),n.appendChild(a);var r=t.overlay?this._overlaysList:this._baseLayersList;return (r.appendChild(n), n);
 },_onInputClick: function(){
  var t,e,i,n=this._form.getElementsByTagName("input"),o=[],s=[];this._handlingClick=!0;for(var a=0,r=n.length;r>a;a++)t=n[a],e=this._layers[t.layerId].layer,i=this._map.hasLayer(e),t.checked&&!i?o.push(e):!t.checked&&i&&s.push(e);for(a=0;a<s.length;a++)this._map.removeLayer(s[a]);for(a=0;a<o.length;a++)this._map.addLayer(o[a]);this._handlingClick=!1,this._refocusOnMap();
 },_expand: function(){
  o.DomUtil.addClass(this._container,"leaflet-control-layers-expanded");
 },_collapse: function(){
  o.DomUtil.removeClass(this._container,"leaflet-control-layers-expanded");
 }}),o.control.layers=function(t,e,i){
  return new o.Control.Layers(t,e,i);
 },o.PosAnimation=o.Evented.extend({run: function(t,e,i,n){
  this.stop(),this._el=t,this._inProgress=!0,this._duration=i||0.25,this._easeOutPower=1/Math.max(n||0.5,0.2),this._startPos=o.DomUtil.getPosition(t),this._offset=e.subtract(this._startPos),this._startTime=+new Date,this.fire("start"),this._animate();
 },stop: function(){
  this._inProgress&&(this._step(!0),this._complete());
 },_animate: function(){
  this._animId=o.Util.requestAnimFrame(this._animate,this),this._step();
 },_step: function(t){
  var e=+new Date-this._startTime,i=1000*this._duration;i>e?this._runFrame(this._easeOut(e/i),t):(this._runFrame(1),this._complete());
 },_runFrame: function(t,e){
  var i=this._startPos.add(this._offset.multiplyBy(t));e&&i._round(),o.DomUtil.setPosition(this._el,i),this.fire("step");
 },_complete: function(){
  o.Util.cancelAnimFrame(this._animId),this._inProgress=!1,this.fire("end");
 },_easeOut: function(t){
  return 1-Math.pow(1-t,this._easeOutPower);
 }}),o.Map.include({setView: function(t,e,n){
  if(e=e===i?this._zoom:this._limitZoom(e),t=this._limitCenter(o.latLng(t),e,this.options.maxBounds),n=n||{},this.stop(),this._loaded&&!n.reset&&n!==!0){
   n.animate!==i&&(n.zoom=o.extend({animate: n.animate},n.zoom),n.pan=o.extend({animate: n.animate},n.pan));var s=this._zoom!==e?this._tryAnimatedZoom&&this._tryAnimatedZoom(t,e,n.zoom):this._tryAnimatedPan(t,n.pan);if(s)return (clearTimeout(this._sizeTimer), this);
  }return (this._resetView(t,e), this);
 },panBy: function(t,e){
  if(t=o.point(t).round(),e=e||{},!t.x&&!t.y)return this;if(e.animate!==!0&&!this.getSize().contains(t))return this._resetView(this.unproject(this.project(this.getCenter()).add(t)),this.getZoom());if(this._panAnim||(this._panAnim=new o.PosAnimation,this._panAnim.on({step: this._onPanTransitionStep,end: this._onPanTransitionEnd},this)),e.noMoveStart||this.fire("movestart"),e.animate!==!1){
   o.DomUtil.addClass(this._mapPane,"leaflet-pan-anim");var i=this._getMapPanePos().subtract(t);this._panAnim.run(this._mapPane,i,e.duration||0.25,e.easeLinearity);
  }else this._rawPanBy(t),this.fire("move").fire("moveend");return this;
 },_onPanTransitionStep: function(){
  this.fire("move");
 },_onPanTransitionEnd: function(){
  o.DomUtil.removeClass(this._mapPane,"leaflet-pan-anim"),this.fire("moveend");
 },_tryAnimatedPan: function(t,e){
  var i=this._getCenterOffset(t)._floor();return(e&&e.animate)===!0||this.getSize().contains(i)?(this.panBy(i,e),(e&&e.animate)!==!1):!1;
 }}),o.Map.mergeOptions({zoomAnimation: !0,zoomAnimationThreshold: 4});var r=o.DomUtil.TRANSITION&&o.Browser.any3d&&!o.Browser.mobileOpera;r&&o.Map.addInitHook(function(){
  this._zoomAnimated=this.options.zoomAnimation,this._zoomAnimated&&(this._createAnimProxy(),o.DomEvent.on(this._proxy,o.DomUtil.TRANSITION_END,this._catchTransitionEnd,this));
 }),o.Map.include(r?{_createAnimProxy: function(){
  var t=this._proxy=o.DomUtil.create("div","leaflet-proxy leaflet-zoom-animated");this._panes.mapPane.appendChild(t),this.on("zoomanim",function(e){
   o.DomUtil.setTransform(t,this.project(e.center,e.zoom),this.getZoomScale(e.zoom,1));
  },this),this.on("load moveend",function(){
   var e=this.getCenter(),i=this.getZoom();o.DomUtil.setTransform(t,this.project(e,i),this.getZoomScale(i,1));
  },this);
 },_catchTransitionEnd: function(t){
  this._animatingZoom&&t.propertyName.indexOf("transform")>=0&&this._onZoomTransitionEnd();
 },_nothingToAnimate: function(){
  return!this._container.getElementsByClassName("leaflet-zoom-animated").length;
 },_tryAnimatedZoom: function(t,e,i){
  if(this._animatingZoom)return!0;if(i=i||{},!this._zoomAnimated||i.animate===!1||this._nothingToAnimate()||Math.abs(e-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),s=this._getCenterOffset(t)._divideBy(1-1/n);return i.animate===!0||this.getSize().contains(s)?(o.Util.requestAnimFrame(function(){
   this.fire("movestart").fire("zoomstart")._animateZoom(t,e,!0);
  },this),!0):!1;
 },_animateZoom: function(t,e,i){
  i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,o.DomUtil.addClass(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center: t,zoom: e,scale: this.getZoomScale(e),origin: this.latLngToLayerPoint(t),offset: this._getCenterOffset(t).multiplyBy(-1)});
 },_onZoomTransitionEnd: function(){
  this._animatingZoom=!1,o.DomUtil.removeClass(this._mapPane,"leaflet-zoom-anim"),this._resetView(this._animateToCenter,this._animateToZoom,!0,!0);
 }}:{}),o.Map.include({flyTo: function(t,e){
  function n(t){
   var e=(v*v-f*f+(t?-1:1)*P*P*g*g)/(2*(t?v:f)*P*g);return Math.log(Math.sqrt(e*e+1)-e);
  }function s(t){
   return(Math.exp(t)-Math.exp(-t))/2;
  }function a(t){
   return(Math.exp(t)+Math.exp(-t))/2;
  }function r(t){
   return s(t)/a(t);
  }function h(t){
   return f*(a(L)/a(L+y*t));
  }function l(t){
   return f*(a(L)*r(L+y*t)-s(L))/P;
  }function u(t){
   return 1-Math.pow(1-t,1.5);
  }function c(){
   var i=(Date.now()-x)/D,n=u(i)*b;1>=i?(this._flyToFrame=o.Util.requestAnimFrame(c,this),this._resetView(this.unproject(d.add(m.subtract(d).multiplyBy(l(n)/g)),p),this.getScaleZoom(f/h(n),p),!0,!0)):this._resetView(t,e,!0,!0);
  }this.stop();var d=this.project(this.getCenter()),m=this.project(t),_=this.getSize(),p=this._zoom;t=o.latLng(t),e=e===i?p:e;var f=Math.max(_.x,_.y),v=f*this.getZoomScale(p,e),g=m.distanceTo(d),y=1.42,P=y*y,L=n(0),x=Date.now(),b=(n(1)-L)/y,D=1000*b*0.8;this.fire("zoomstart"),c.call(this);
 }});
}(window,document);
L.Icon.Label = L.Icon.extend({
	options: {
		/*
		labelAnchor: (Point) (top left position of the label within the wrapper, default is right)
		wrapperAnchor: (Point) (position of icon and label relative to Lat/Lng)
		iconAnchor: (Point) (top left position of icon within wrapper)
		labelText: (String) (label's text component, if this is null the element will not be created)
		*/
		/* Icon options:
		iconUrl: (String) (required)
		iconSize: (Point) (can be set through CSS)
		iconAnchor: (Point) (centered by default if size is specified, can be set in CSS with negative margins)
		popupAnchor: (Point) (if not specified, popup opens in the anchor point)
		shadowUrl: (Point) (no shadow by default)
		shadowSize: (Point)
		*/
		labelClassName: ""
	},
	
	initialize: function (options) {
        L.Util.setOptions(this, options);
        L.Icon.prototype.initialize.call(this, this.options);
    },

	setLabelAsHidden: function () {
        this._labelHidden = true;
    },

	createIcon: function () {
        return this._createLabel(L.Icon.prototype.createIcon.call(this));
    },
	
	createShadow: function () {
        if (!this.options.shadowUrl) {
            return null;
        }
        var shadow = L.Icon.prototype.createShadow.call(this);
        //need to reposition the shadow
        if (shadow) {
            shadow.style.marginLeft = (-this.options.wrapperAnchor.x) + "px";
            shadow.style.marginTop = (-this.options.wrapperAnchor.y) + "px";
        }
        return shadow;
    },

	updateLabel: function (icon, text) {
        if (icon.nodeName.toUpperCase() === "DIV") {
            icon.childNodes[1].innerHTML = text;

            this.options.labelText = text;
        }
    },

	showLabel: function (icon) {
        if (!this._labelTextIsSet()) {
            return;
        }

        icon.childNodes[1].style.display = "block";
    },

	hideLabel: function (icon) {
        if (!this._labelTextIsSet()) {
            return;
        }

        icon.childNodes[1].style.display = "none";
    },

	_createLabel: function (img) {
        if (!this._labelTextIsSet()) {
            return img;
        }

        var wrapper = document.createElement("div"),
			label = document.createElement("span");

        // set up wrapper anchor
        wrapper.style.marginLeft = (-this.options.wrapperAnchor.x) + "px";
        wrapper.style.marginTop = (-this.options.wrapperAnchor.y) + "px";

        wrapper.className = "leaflet-marker-icon-wrapper leaflet-zoom-animated";

        // set up label
        label.className = "leaflet-marker-iconlabel " + this.options.labelClassName;

        label.innerHTML = this.options.labelText;

        label.style.marginLeft = this.options.labelAnchor.x + "px";
        label.style.marginTop = this.options.labelAnchor.y + "px";

        if (this._labelHidden) {
            label.style.display = "none";
            // Ensure that the pointer cursor shows
            img.style.cursor = "pointer";
        }

        //reset icons margins (as super makes them -ve)
        img.style.marginLeft = this.options.iconAnchor.x + "px";
        img.style.marginTop = this.options.iconAnchor.y + "px";

        wrapper.appendChild(img);
        wrapper.appendChild(label);

        return wrapper;
    },
	
	_labelTextIsSet: function () {
        return typeof this.options.labelText !== "undefined" && this.options.labelText !== null;
    }
});

L.Icon.Label.Default = L.Icon.Label.extend({
	options: {
		//This is the top left position of the label within the wrapper. By default it will display at the right
		//middle position of the default icon. x = width of icon + padding
		//If the icon height is greater than the label height you will need to set the y value.
		//y = (icon height - label height) / 2
		labelAnchor: new L.Point(29, 8),
		
		//This is the position of the wrapper div. Use this to position icon + label relative to the Lat/Lng.
		//By default the point of the default icon is anchor
		wrapperAnchor: new L.Point(13, 41),
		
		//This is now the top left position of the icon within the wrapper.
		//If the label height is greater than the icon you will need to set the y value.
		//y = (label height - icon height) / 2
		iconAnchor: new L.Point(0, 0),
		
		//label's text component, if this is null the element will not be created
		labelText: null,
		
		/* From L.Icon.Default */
		iconUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAGmklEQVRYw7VXeUyTZxjvNnfELFuyIzOabermMZEeQC/OclkO49CpOHXOLJl/CAURuYbQi3KLgEhbrhZ1aDwmaoGqKII6odATmH/scDFbdC7LvFqOCc+e95s2VG50X/LLm/f4/Z7neY/ne18aANCmAr5E/xZf1uDOkTcGcWR6hl9247tT5U7Y6SNvWsKT63P58qbfeLJG8M5qcgTknrvvrdDbsT7Ml+tv82X6vVxJE33aRmgSyYtcWVMqX97Yv2JvW39UhRE2HuyBL+t+gK1116ly06EeWFNlAmHxlQE0OMiV6mQCScusKRlhS3QLeVJdl1+23h5dY4FNB3thrbYboqptEFlphTC1hSpJnbRvxP4NWgsE5Jyz86QNNi/5qSUTGuFk1gu54tN9wuK2wc3o+Wc13RCmsoBwEqzGcZsxsvCSy/9wJKf7UWf1mEY8JWfewc67UUoDbDjQC+FqK4QqLVMGGR9d2wurKzqBk3nqIT/9zLxRRjgZ9bqQgub+DdoeCC03Q8j+0QhFhBHR/eP3U/zCln7Uu+hihJ1+bBNffLIvmkyP0gpBZWYXhKussK6mBz5HT6M1Nqpcp+mBCPXosYQfrekGvrjewd59/GvKCE7TbK/04/ZV5QZYVWmDwH1mF3xa2Q3ra3DBC5vBT1oP7PTj4C0+CcL8c7C2CtejqhuCnuIQHaKHzvcRfZpnylFfXsYJx3pNLwhKzRAwAhEqG0SpusBHfAKkxw3w4627MPhoCH798z7s0ZnBJ/MEJbZSbXPhER2ih7p2ok/zSj2cEJDd4CAe+5WYnBCgR2uruyEw6zRoW6/DWJ/OeAP8pd/BGtzOZKpG8oke0SX6GMmRk6GFlyAc59K32OTEinILRJRchah8HQwND8N435Z9Z0FY1EqtxUg+0SO6RJ/mmXz4VuS+DpxXC3gXmZwIL7dBSH4zKE50wESf8qwVgrP1EIlTO5JP9Igu0aexdh28F1lmAEGJGfh7jE6ElyM5Rw/FDcYJjWhbeiBYoYNIpc2FT/SILivp0F1ipDWk4BIEo2VuodEJUifhbiltnNBIXPUFCMpthtAyqws/BPlEF/VbaIxErdxPphsU7rcCp8DohC+GvBIPJS/tW2jtvTmmAeuNO8BNOYQeG8G/2OzCJ3q+soYB5i6NhMaKr17FSal7GIHheuV3uSCY8qYVuEm1cOzqdWr7ku/R0BDoTT+DT+ohCM6/CCvKLKO4RI+dXPeAuaMqksaKrZ7L3FE5FIFbkIceeOZ2OcHO6wIhTkNo0ffgjRGxEqogXHYUPHfWAC/lADpwGcLRY3aeK4/oRGCKYcZXPVoeX/kelVYY8dUGf8V5EBRbgJXT5QIPhP9ePJi428JKOiEYhYXFBqou2Guh+p/mEB1/RfMw6rY7cxcjTrneI1FrDyuzUSRm9miwEJx8E/gUmqlyvHGkneiwErR21F3tNOK5Tf0yXaT+O7DgCvALTUBXdM4YhC/IawPU+2PduqMvuaR6eoxSwUk75ggqsYJ7VicsnwGIkZBSXKOUww73WGXyqP+J2/b9c+gi1YAg/xpwck3gJuucNrh5JvDPvQr0WFXf0piyt8f8/WI0hV4pRxxkQZdJDfDJNOAmM0Ag8jyT6hz0WGXWuP94Yh2jcfjmXAGvHCMslRimDHYuHuDsy2QtHuIavznhbYURq5R57KpzBBRZKPJi8eQg48h4j8SDdowifdIrEVdU+gbO6QNvRRt4ZBthUaZhUnjlYObNagV3keoeru3rU7rcuceqU1mJBxy+BWZYlNEBH+0eH4vRiB+OYybU2hnblYlTvkHinM4m54YnxSyaZYSF6R3jwgP7udKLGIX6r/lbNa9N6y5MFynjWDtrHd75ZvTYAPO/6RgF0k76mQla3FGq7dO+cH8sKn0Vo7nDllwAhqwLPkxrHwWmHJOo+AKJ4rab5OgrM7rVu8eWb2Pu0Dh4eDgXoOfvp7Y7QeqknRmvcTBEyq9m/HQQSCSz6LHq3z0yzsNySRfMS253wl2KyRDbcZPcfJKjZmSEOjcxyi+Y8dUOtsIEH6R2wNykdqrkYJ0RV92H0W58pkfQk7cKevsLK10Py8SdMGfXNXATY+pPbyJR/ET6n9nIfztNtZYRV9XniQu9IA2vOVgy4ir7GCLVmmd+zjkH0eAF9Po6K61pmCXHxU5rHMYd1ftc3owjwRSVRzLjKvqZEty6cRUD7jGqiOdu5HG6MdHjNcNYGqfDm5YRzLBBCCDl/2bk8a8gdbqcfwECu62Fg/HrggAAAABJRU5ErkJggg==",//L.Icon.Default.imagePath + '/marker-icon.png',
		iconSize: new L.Point(25, 41),
		popupAnchor: new L.Point(0, -33),

		shadowUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAApCAYAAACoYAD2AAAC5ElEQVRYw+2YW4/TMBCF45S0S1luXZCABy5CgLQgwf//S4BYBLTdJLax0fFqmB07nnQfEGqkIydpVH85M+NLjPe++dcPc4Q8Qh4hj5D/AaQJx6H/4TMwB0PeBNwU7EGQAmAtsNfAzoZkgIa0ZgLMa4Aj6CxIAsjhjOCoL5z7Glg1JAOkaicgvQBXuncwJAWjksLtBTWZe04CnYRktUGdilALppZBOgHGZcBzL6OClABvMSVIzyBjazOgrvACf1ydC5mguqAVg6RhdkSWQFj2uxfaq/BrIZOLEWgZdALIDvcMcZLD8ZbLC9de4yR1sYMi4G20S4Q/PWeJYxTOZn5zJXANZHIxAd4JWhPIloTJZhzMQduM89WQ3MUVAE/RnhAXpTycqys3NZALOBbB7kFrgLesQl2h45Fcj8L1tTSohUwuxhy8H/Qg6K7gIs+3kkaigQCOcyEXCHN07wyQazhrmIulvKMQAwMcmLNqyCVyMAI+BuxSMeTk3OPikLY2J1uE+VHQk6ANrhds+tNARqBeaGc72cK550FP4WhXmFmcMGhTwAR1ifOe3EvPqIegFmF+C8gVy0OfAaWQPMR7gF1OQKqGoBjq90HPMP01BUjPOqGFksC4emE48tWQAH0YmvOgF3DST6xieJgHAWxPAHMuNhrImIdvoNOKNWIOcE+UXE0pYAnkX6uhWsgVXDxHdTfCmrEEmMB2zMFimLVOtiiajxiGWrbU52EeCdyOwPEQD8LqyPH9Ti2kgYMf4OhSKB7qYILbBv3CuVTJ11Y80oaseiMWOONc/Y7kJYe0xL2f0BaiFTxknHO5HaMGMublKwxFGzYdWsBF174H/QDknhTHmHHN39iWFnkZx8lPyM8WHfYELmlLKtgWNmFNzQcC1b47gJ4hL19i7o65dhH0Negbca8vONZoP7doIeOC9zXm8RjuL0Gf4d4OYaU5ljo3GYiqzrWQHfJxA6ALhDpVKv9qYeZA8eM3EhfPSCmpuD0AAAAASUVORK5CYII=",//L.Icon.Default.imagePath + '/marker-shadow.png',
		shadowSize: new L.Point(41, 41)
	}
});

L.Marker.Label = L.Marker.extend({
	updateLabel: function (text) {
        this.options.icon.updateLabel(this._icon, text);
    },

	_initIcon: function () {
        if (!(this.options.icon instanceof L.Icon.Label)) {
            throw new Error("Icon must be an instance of L.Icon.Label.");
        }

        // Ensure that the label is hidden to begin with
        if (this.options.revealing) {
            this.options.icon.setLabelAsHidden();
        }

        L.Marker.prototype._initIcon.call(this);
    },

	_removeIcon: function () {
        if (this.options.revealing) {
            L.DomEvent
				.off(this._icon, "mouseover", this._showLabel)
				.off(this._icon, "mouseout", this._hideLabel);
        }

        L.Marker.prototype._removeIcon.call(this);
    },

	_initInteraction: function () {
        L.Marker.prototype._initInteraction.call(this);

        if (!this.options.revealing) {
            return;
        }

        L.DomEvent
			.on(this._icon, "mouseover", this._showLabel, this)
			.on(this._icon, "mouseout", this._hideLabel, this);
    },

	_showLabel: function () {
        this.options.icon.showLabel(this._icon);
    },

	_hideLabel: function () {
        this.options.icon.hideLabel(this._icon);
    }
});
var Mapper = (function(L,google){
    if (!L) return false;
    var transform = function(val){
        var fn;
        try{
            fn = new Function("return "+ val +";");
        } catch (e){
            fn = function(){
                return undefined;
            }
        }

        return fn();
    };

    var googlemaps_available = google && google.maps && google.maps.StreetViewService;

    var getType= (function () {
        var stringConstructor = "".constructor
			, arrayConstructor = [].constructor
			, objectConstructor = {}.constructor
			, functionConstructor = function () {}.constructor
			, _type = "";
        var getType = function(value){
            if (value === null) {
                _type = "null";
            }
			else if (value === undefined) {
                _type = "undefined";
            }
			else if (value.constructor === stringConstructor) {
                _type = "string";
            }
			else if (value.constructor === arrayConstructor) {
                _type = "array";
            }
			else if (value.constructor === objectConstructor) {
                _type = "object";
            }
			else if (value.constructor === functionConstructor) {
                _type = "function";
            }
			else if (value.nodeType !== undefined) {
                _type = "html";
            }

            return _type;
        };

        return getType;
    })();

    var providers = (function(){
        return {
			OSM: {name: "OpenStreetMap",tiles: function(){
                return L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png");
            }}
			, MB: {name: "MapBox",tiles: function(){
            return L.tileLayer("https://{s}.tiles.mapbox.com/v3/mjzzanichelli.jkm5b041/{z}/{x}/{y}.png");
        }}
			, GMH: {name: "Google Maps Hybrid",tiles: function(){
            return L.tileLayer("https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}");
        }}
			, GMS: {name: "Google Maps Satellite",tiles: function(){
            return L.tileLayer("https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}");
        }}
			, GMR: {name: "Google Maps Roadmap",tiles: function(){
            return L.tileLayer("https://mt1.google.com/vt/lyrs=r&x={x}&y={y}&z={z}");
        }}
			, GMT: {name: "Google Maps Terrain",tiles: function(){
            return L.tileLayer("https://mt1.google.com/vt/lyrs=t&x={x}&y={y}&z={z}");
        }}
		}
    })();

    var assets = (function(){
        return {
			marker: {
				url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkJCN0NGODYwQzk4NTExRTRBMzg4RDI3OUVCRUMxOUMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkJCN0NGODYxQzk4NTExRTRBMzg4RDI3OUVCRUMxOUMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkI3Q0Y4NUVDOTg1MTFFNEEzODhEMjc5RUJFQzE5QzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkI3Q0Y4NUZDOTg1MTFFNEEzODhEMjc5RUJFQzE5QzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6SLYwiAAAE4UlEQVR42syYa2wUVRTH77073S2LkqpQE0pqlCgtQeMnFAOJkQ8aQoL7kRobEoyJkcREg48AklgSDSaNr2BD3A9KVSjK1rJi/UArkShaFetKCzUN1rJrpd12+9jdeV/Pnb3TToeZfXQfYZKTnZ1k7vnN/9x7zzkXU0rRzXwJ5g3G+KaDY+IJRbyPHWx+bKv5W4Zcw5Q6cF9+ChYIRar3hOtxTV0AC94tiHjWw+M7IQwr4LNngGkC6dolqsrnaCLaCRAj8I6eC9bRoTkH8wgxMcBe6F5PblvTgjxV2/mzXJeONCWsT107IL77xAD772+5oi8ouC5riPMBNBTzBt68Vbh/21tI8O1egvLsUpEqBdXImVfl0GuzBugbl2nq9YaiADPhfC60ltTeG8qEsshL1y7r1//aIX4YGDbDvlTADNwzn91N1jzwHcKkrnTLU4/q1/54VPyo6Wo2SMaWbQ4R77b9NWT1hi5grUPsQ0plMB6Me5qNn2sekyzPBeHBHa0gbSN8MSq5YdxgjJ+Zz6SQVcxuPMv2hDfj2+t7bPtb6ffiyX8eS3+w/Tzca/ZQu4WYAQl4Re0++FJcFvUWDBt+MirifENMfE8fXQv73FZbQiiPgR/Dn0uYiYN6HrLqnicroN68iuAvwPw6qegIiAXflgrBGQb+NrsBCk57HyKkwXi5Uhch67hYeQIishLplawTyapCADHsPf4sGagcu43PoWQztj7npK+r45DaaivHp1/PN5MYa5/K6YuVXCTgL2LxnxNQp8l4T0UBkxO9FjicC1BTfzlxCsqiVEUAwY9yob2TVzXIDukIqPz+VZymEx0VUW9uolP985vpghQEU6DyfQdRTSyzepLyU3ubhcW6krFbLmaQinw+OApfd7ScgPr48OdK/+m4Bcxj326IY5OTUVGSug+3IlUeLc/KTf4ndh381AJGHFR0LRSNMGuj/dPa2ODLMCAtMSBVL4ba6Oy4upC95gtXkk9Fbc5FSfzilR6aShwrZcmvxQZ65R/bI9wPsdmieUiy9rOsVURIFMMtB5EqDpRm1cajUvjQSUsFjV3yMEY5GhZTRVkfuzKtDpx9HlLgXFGAqiRKPe8HqTjD+mKJj6+5dHY0F6CposJUlM61XdL+HXyxiPlIld9OfayN/Mr64Tk2JodUuR/dAmrC0vyOLsxQh/aH9UTsvSXNu6t9XfLPx7+HcRJgTMEUWJpFiIugWSBzLhK71CofKJ3ueKmVpqa+Lmi/i4/8IHYfbof3J8Amwaa5immuomxR0qpg3odH5kSuAvOTmrqV1YFDx7DXvzHn16WmIumTe/dRcTbBgczQKhY4hQMqNhXzCvGiFMgc6InopNR75FmkiENZV6w0Nyx++/ZegItx9aa4ekluog3Qulhoocdv2DItqpmSQuPWu3ybmr+E1rH+xrMsaVTsPbJL+7svagFRLZlKc7indkBSSN1r+WWhSaqDZ0eU/q6dSFdii3pdTR6T+040A9wwV22GK5a2zTtTOc0JrlAFbzjMBGO9xDLvxp2NVRseP46IsBr2ypgSOdMk93UMWZTTbB07ss4zJ7BF5x9LPOnHPH9Cg4Xu8D781Kblu4IXvA81PQL/WZd2C/+AKl4MeFyKAlyqI+Bsq9vLYTxm9uHmeva3fPcnxvNksDmrg/8FGAD/P5mnq5y2nAAAAABJRU5ErkJggg=="
				, retina_url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkJCN0NGODYwQzk4NTExRTRBMzg4RDI3OUVCRUMxOUMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkJCN0NGODYxQzk4NTExRTRBMzg4RDI3OUVCRUMxOUMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkI3Q0Y4NUVDOTg1MTFFNEEzODhEMjc5RUJFQzE5QzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkI3Q0Y4NUZDOTg1MTFFNEEzODhEMjc5RUJFQzE5QzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6SLYwiAAAE4UlEQVR42syYa2wUVRTH77073S2LkqpQE0pqlCgtQeMnFAOJkQ8aQoL7kRobEoyJkcREg48AklgSDSaNr2BD3A9KVSjK1rJi/UArkShaFetKCzUN1rJrpd12+9jdeV/Pnb3TToeZfXQfYZKTnZ1k7vnN/9x7zzkXU0rRzXwJ5g3G+KaDY+IJRbyPHWx+bKv5W4Zcw5Q6cF9+ChYIRar3hOtxTV0AC94tiHjWw+M7IQwr4LNngGkC6dolqsrnaCLaCRAj8I6eC9bRoTkH8wgxMcBe6F5PblvTgjxV2/mzXJeONCWsT107IL77xAD772+5oi8ouC5riPMBNBTzBt68Vbh/21tI8O1egvLsUpEqBdXImVfl0GuzBugbl2nq9YaiADPhfC60ltTeG8qEsshL1y7r1//aIX4YGDbDvlTADNwzn91N1jzwHcKkrnTLU4/q1/54VPyo6Wo2SMaWbQ4R77b9NWT1hi5grUPsQ0plMB6Me5qNn2sekyzPBeHBHa0gbSN8MSq5YdxgjJ+Zz6SQVcxuPMv2hDfj2+t7bPtb6ffiyX8eS3+w/Tzca/ZQu4WYAQl4Re0++FJcFvUWDBt+MirifENMfE8fXQv73FZbQiiPgR/Dn0uYiYN6HrLqnicroN68iuAvwPw6qegIiAXflgrBGQb+NrsBCk57HyKkwXi5Uhch67hYeQIishLplawTyapCADHsPf4sGagcu43PoWQztj7npK+r45DaaivHp1/PN5MYa5/K6YuVXCTgL2LxnxNQp8l4T0UBkxO9FjicC1BTfzlxCsqiVEUAwY9yob2TVzXIDukIqPz+VZymEx0VUW9uolP985vpghQEU6DyfQdRTSyzepLyU3ubhcW6krFbLmaQinw+OApfd7ScgPr48OdK/+m4Bcxj326IY5OTUVGSug+3IlUeLc/KTf4ndh381AJGHFR0LRSNMGuj/dPa2ODLMCAtMSBVL4ba6Oy4upC95gtXkk9Fbc5FSfzilR6aShwrZcmvxQZ65R/bI9wPsdmieUiy9rOsVURIFMMtB5EqDpRm1cajUvjQSUsFjV3yMEY5GhZTRVkfuzKtDpx9HlLgXFGAqiRKPe8HqTjD+mKJj6+5dHY0F6CposJUlM61XdL+HXyxiPlIld9OfayN/Mr64Tk2JodUuR/dAmrC0vyOLsxQh/aH9UTsvSXNu6t9XfLPx7+HcRJgTMEUWJpFiIugWSBzLhK71CofKJ3ueKmVpqa+Lmi/i4/8IHYfbof3J8Amwaa5immuomxR0qpg3odH5kSuAvOTmrqV1YFDx7DXvzHn16WmIumTe/dRcTbBgczQKhY4hQMqNhXzCvGiFMgc6InopNR75FmkiENZV6w0Nyx++/ZegItx9aa4ekluog3Qulhoocdv2DItqpmSQuPWu3ybmr+E1rH+xrMsaVTsPbJL+7svagFRLZlKc7indkBSSN1r+WWhSaqDZ0eU/q6dSFdii3pdTR6T+040A9wwV22GK5a2zTtTOc0JrlAFbzjMBGO9xDLvxp2NVRseP46IsBr2ypgSOdMk93UMWZTTbB07ss4zJ7BF5x9LPOnHPH9Cg4Xu8D781Kblu4IXvA81PQL/WZd2C/+AKl4MeFyKAlyqI+Bsq9vLYTxm9uHmeva3fPcnxvNksDmrg/8FGAD/P5mnq5y2nAAAAABJRU5ErkJggg=="
				, size: {
					width: 40
					, height: 40
				}
				, anchor: {
					width: 0
					, height: 0
				}
			}
			, preferred_marker: {
				url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkJCN0NGODYwQzk4NTExRTRBMzg4RDI3OUVCRUMxOUMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkJCN0NGODYxQzk4NTExRTRBMzg4RDI3OUVCRUMxOUMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkI3Q0Y4NUVDOTg1MTFFNEEzODhEMjc5RUJFQzE5QzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkI3Q0Y4NUZDOTg1MTFFNEEzODhEMjc5RUJFQzE5QzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6SLYwiAAAE4UlEQVR42syYa2wUVRTH77073S2LkqpQE0pqlCgtQeMnFAOJkQ8aQoL7kRobEoyJkcREg48AklgSDSaNr2BD3A9KVSjK1rJi/UArkShaFetKCzUN1rJrpd12+9jdeV/Pnb3TToeZfXQfYZKTnZ1k7vnN/9x7zzkXU0rRzXwJ5g3G+KaDY+IJRbyPHWx+bKv5W4Zcw5Q6cF9+ChYIRar3hOtxTV0AC94tiHjWw+M7IQwr4LNngGkC6dolqsrnaCLaCRAj8I6eC9bRoTkH8wgxMcBe6F5PblvTgjxV2/mzXJeONCWsT107IL77xAD772+5oi8ouC5riPMBNBTzBt68Vbh/21tI8O1egvLsUpEqBdXImVfl0GuzBugbl2nq9YaiADPhfC60ltTeG8qEsshL1y7r1//aIX4YGDbDvlTADNwzn91N1jzwHcKkrnTLU4/q1/54VPyo6Wo2SMaWbQ4R77b9NWT1hi5grUPsQ0plMB6Me5qNn2sekyzPBeHBHa0gbSN8MSq5YdxgjJ+Zz6SQVcxuPMv2hDfj2+t7bPtb6ffiyX8eS3+w/Tzca/ZQu4WYAQl4Re0++FJcFvUWDBt+MirifENMfE8fXQv73FZbQiiPgR/Dn0uYiYN6HrLqnicroN68iuAvwPw6qegIiAXflgrBGQb+NrsBCk57HyKkwXi5Uhch67hYeQIishLplawTyapCADHsPf4sGagcu43PoWQztj7npK+r45DaaivHp1/PN5MYa5/K6YuVXCTgL2LxnxNQp8l4T0UBkxO9FjicC1BTfzlxCsqiVEUAwY9yob2TVzXIDukIqPz+VZymEx0VUW9uolP985vpghQEU6DyfQdRTSyzepLyU3ubhcW6krFbLmaQinw+OApfd7ScgPr48OdK/+m4Bcxj326IY5OTUVGSug+3IlUeLc/KTf4ndh381AJGHFR0LRSNMGuj/dPa2ODLMCAtMSBVL4ba6Oy4upC95gtXkk9Fbc5FSfzilR6aShwrZcmvxQZ65R/bI9wPsdmieUiy9rOsVURIFMMtB5EqDpRm1cajUvjQSUsFjV3yMEY5GhZTRVkfuzKtDpx9HlLgXFGAqiRKPe8HqTjD+mKJj6+5dHY0F6CposJUlM61XdL+HXyxiPlIld9OfayN/Mr64Tk2JodUuR/dAmrC0vyOLsxQh/aH9UTsvSXNu6t9XfLPx7+HcRJgTMEUWJpFiIugWSBzLhK71CofKJ3ueKmVpqa+Lmi/i4/8IHYfbof3J8Amwaa5immuomxR0qpg3odH5kSuAvOTmrqV1YFDx7DXvzHn16WmIumTe/dRcTbBgczQKhY4hQMqNhXzCvGiFMgc6InopNR75FmkiENZV6w0Nyx++/ZegItx9aa4ekluog3Qulhoocdv2DItqpmSQuPWu3ybmr+E1rH+xrMsaVTsPbJL+7svagFRLZlKc7indkBSSN1r+WWhSaqDZ0eU/q6dSFdii3pdTR6T+040A9wwV22GK5a2zTtTOc0JrlAFbzjMBGO9xDLvxp2NVRseP46IsBr2ypgSOdMk93UMWZTTbB07ss4zJ7BF5x9LPOnHPH9Cg4Xu8D781Kblu4IXvA81PQL/WZd2C/+AKl4MeFyKAlyqI+Bsq9vLYTxm9uHmeva3fPcnxvNksDmrg/8FGAD/P5mnq5y2nAAAAABJRU5ErkJggg=="
				, retina_url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkJCN0NGODYwQzk4NTExRTRBMzg4RDI3OUVCRUMxOUMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkJCN0NGODYxQzk4NTExRTRBMzg4RDI3OUVCRUMxOUMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkI3Q0Y4NUVDOTg1MTFFNEEzODhEMjc5RUJFQzE5QzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkI3Q0Y4NUZDOTg1MTFFNEEzODhEMjc5RUJFQzE5QzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6SLYwiAAAE4UlEQVR42syYa2wUVRTH77073S2LkqpQE0pqlCgtQeMnFAOJkQ8aQoL7kRobEoyJkcREg48AklgSDSaNr2BD3A9KVSjK1rJi/UArkShaFetKCzUN1rJrpd12+9jdeV/Pnb3TToeZfXQfYZKTnZ1k7vnN/9x7zzkXU0rRzXwJ5g3G+KaDY+IJRbyPHWx+bKv5W4Zcw5Q6cF9+ChYIRar3hOtxTV0AC94tiHjWw+M7IQwr4LNngGkC6dolqsrnaCLaCRAj8I6eC9bRoTkH8wgxMcBe6F5PblvTgjxV2/mzXJeONCWsT107IL77xAD772+5oi8ouC5riPMBNBTzBt68Vbh/21tI8O1egvLsUpEqBdXImVfl0GuzBugbl2nq9YaiADPhfC60ltTeG8qEsshL1y7r1//aIX4YGDbDvlTADNwzn91N1jzwHcKkrnTLU4/q1/54VPyo6Wo2SMaWbQ4R77b9NWT1hi5grUPsQ0plMB6Me5qNn2sekyzPBeHBHa0gbSN8MSq5YdxgjJ+Zz6SQVcxuPMv2hDfj2+t7bPtb6ffiyX8eS3+w/Tzca/ZQu4WYAQl4Re0++FJcFvUWDBt+MirifENMfE8fXQv73FZbQiiPgR/Dn0uYiYN6HrLqnicroN68iuAvwPw6qegIiAXflgrBGQb+NrsBCk57HyKkwXi5Uhch67hYeQIishLplawTyapCADHsPf4sGagcu43PoWQztj7npK+r45DaaivHp1/PN5MYa5/K6YuVXCTgL2LxnxNQp8l4T0UBkxO9FjicC1BTfzlxCsqiVEUAwY9yob2TVzXIDukIqPz+VZymEx0VUW9uolP985vpghQEU6DyfQdRTSyzepLyU3ubhcW6krFbLmaQinw+OApfd7ScgPr48OdK/+m4Bcxj326IY5OTUVGSug+3IlUeLc/KTf4ndh381AJGHFR0LRSNMGuj/dPa2ODLMCAtMSBVL4ba6Oy4upC95gtXkk9Fbc5FSfzilR6aShwrZcmvxQZ65R/bI9wPsdmieUiy9rOsVURIFMMtB5EqDpRm1cajUvjQSUsFjV3yMEY5GhZTRVkfuzKtDpx9HlLgXFGAqiRKPe8HqTjD+mKJj6+5dHY0F6CposJUlM61XdL+HXyxiPlIld9OfayN/Mr64Tk2JodUuR/dAmrC0vyOLsxQh/aH9UTsvSXNu6t9XfLPx7+HcRJgTMEUWJpFiIugWSBzLhK71CofKJ3ueKmVpqa+Lmi/i4/8IHYfbof3J8Amwaa5immuomxR0qpg3odH5kSuAvOTmrqV1YFDx7DXvzHn16WmIumTe/dRcTbBgczQKhY4hQMqNhXzCvGiFMgc6InopNR75FmkiENZV6w0Nyx++/ZegItx9aa4ekluog3Qulhoocdv2DItqpmSQuPWu3ybmr+E1rH+xrMsaVTsPbJL+7svagFRLZlKc7indkBSSN1r+WWhSaqDZ0eU/q6dSFdii3pdTR6T+040A9wwV22GK5a2zTtTOc0JrlAFbzjMBGO9xDLvxp2NVRseP46IsBr2ypgSOdMk93UMWZTTbB07ss4zJ7BF5x9LPOnHPH9Cg4Xu8D781Kblu4IXvA81PQL/WZd2C/+AKl4MeFyKAlyqI+Bsq9vLYTxm9uHmeva3fPcnxvNksDmrg/8FGAD/P5mnq5y2nAAAAABJRU5ErkJggg=="
				, size: {
					width: 40
					, height: 40
				}
				, anchor: {
					width: 0
					, height: 0
				}
			}
			, locator: {
				url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkNGRTQ0NTU0Qzk4NTExRTQ5QkM2QzZFRTQzNjE3REVFIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkNGRTQ0NTU1Qzk4NTExRTQ5QkM2QzZFRTQzNjE3REVFIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Q0ZFNDQ1NTJDOTg1MTFFNDlCQzZDNkVFNDM2MTdERUUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6Q0ZFNDQ1NTNDOTg1MTFFNDlCQzZDNkVFNDM2MTdERUUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz40odP0AAAFfklEQVR42sxYe0wcRRj/dqFHOVoNxWibBiTUSIsxMaLWmCakesQHGm1jNUb/aKyB2kRr4z8qiY/ER9s/LC02pCSNLQZtREI0RmmlTalITBvAFmyqtkDBQI/SUjjuuNfu+M3ccMzt7ezecph0kt/N3sw3u7/5XvNQCCFwMxcVbvKSme4LhncoaY3P30P+H4JIrACrZxHrEGsQdyAWISYRg4huxDFEG0Kb73cUpz44/JayFqv3EU+k6CJexD6O6SQN1pCFITi0XVmCVQ3iVTpuHsoYQryG+EVsLNhL0g+SoTeVQiBwGrEFoQB9p3MUIFoR7ya0pxvFSO4urDq4ny1E1vgU8fGCRPHlN5hZf0SsXODsUY0YQBxML83osAd/i23V4s4FV0Epew5eaEuVJA2aU4h/5kVwcBuL1i1Wg7NXe2DJukrIuX9TQru/uwmmO+phxpqsG7EX8dS8onjwdYWatkI2cCkSy3v5gKWKrjVWgQ+J2pSHCuvIGUdBMrBVyUfeT1LuZnCjxozkQkNdDGKhMlRW9h6OSudRTGAjQpWljGUbds4Ru9wFw9WrYOSTBxjoM22bLUzWOv1sGKhSVEcEiQ5lCDDD4mIPZN5WFIuhwASMfl4OkbH+eD99pm20jzk5yrryS0H2PkQe4l6nGiyRzTjrztK42FR7Pej+iSQZ2kb74sG0xmOnxRJHUYwzWiEbIMaUhkSoFswK7RPHyOR4WeHMxATcMqcWP5xd4pE6P+1LmIh1oLgURQEzyEw8KjNHFH0snsiQxC1llUkytM0tEAwNdNmZeMypic/SnZBZn7+3jfmYmpPL/t+++QDzy8CfsaTsvscDt66fyxxUNtjfZWnfqA69fIdEUltJCPyMv0/LXug73ZRAgj6L/42yNrsWb10v9Bi2cMQuzXyLCMpSg+/3ppR3BVTWIsVAJArf1J6LrWoCScWS4N2NZBwd94jMqamZI4IvykoQfY/KWgRHtO86fMktqRpI2uwHddyz6RAFnT0n4fr3u2wJTrbVg2w8xXQIml88Bv/ys4xIMq5FKcHiI+QSzrBeNvsJ/HjEK9ci7aMy0nSFLtTwN9Si6GJOMINDsTWxoMVqxFWZBsYa35EOvVJfZam9izfg8L4+oEk1C+GSmdmS4OomcgNnu12mhanOJvCfS97z0bbps3Lf84VhsLIDaKRlc3KiiVVHZ5KSZgwWHVpkUThaV5W4xE1PsDaZvKaBtv881HpnmJYWCeZVTTSopHSq80dwz0bQmU1WgfCVfhj7as7U11p2sTbZqvGbF747fJEd7EVSqslRVknpXKzQBRFL1zNQlqWyW4IMM7nCj2LH3cEPyqXvGglAX8Vx+CyiQ4DOmx/kfbymbUFEmC4us7cRqRCMJ9HuCnjbpcJuMznX8iJmXgqzEojC+OZOeO/8JIxzIiLJgEAwwgnScCKObrde6YAanL1pAg+N9kPUNyFLKaEv/oKdSG6Uk6JkZjjCnJQmxLnj6zemZvyA3nAJKnUdzji4USBHR2B3Qz+7TKIXS1PcrH5OMCSYVTfeOTgx8WytHlwLy0uXQbuqQJHdzC5Mwf4XOuAQ/7jGtTWLkKDBKK9FLZJUCYqRxSLupzK4b6UbWrEhT3rsDMHX60/Ah/G0H0NUIBoVoHEk3Nw4IagYXEM5+Sg8nOuCo/wQnhgUGvzw3K+wzRuM3w0SgaQm+Jz4LJrXMUEjSRbZnY/B4zmZ0MJXhFiyJnByRw9sar/KzCf6MRGI6AbSYCQ3nztq4wzJI8ehNaLBS/gvDLGoPdU8DBuRnI/7V1jwtbDBtEbNJV/KUQ1awe6GNp4jPfB8TzmcOPQgLBV2JpkcGQKMS5r1ZWiaBOGP8hjoh7auSvqwFMI4y/KfAAMADLPeID+rYAgAAAAASUVORK5CYII="
				, retina_url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkNGRTQ0NTU0Qzk4NTExRTQ5QkM2QzZFRTQzNjE3REVFIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkNGRTQ0NTU1Qzk4NTExRTQ5QkM2QzZFRTQzNjE3REVFIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6Q0ZFNDQ1NTJDOTg1MTFFNDlCQzZDNkVFNDM2MTdERUUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6Q0ZFNDQ1NTNDOTg1MTFFNDlCQzZDNkVFNDM2MTdERUUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz40odP0AAAFfklEQVR42sxYe0wcRRj/dqFHOVoNxWibBiTUSIsxMaLWmCakesQHGm1jNUb/aKyB2kRr4z8qiY/ER9s/LC02pCSNLQZtREI0RmmlTalITBvAFmyqtkDBQI/SUjjuuNfu+M3ccMzt7ezecph0kt/N3sw3u7/5XvNQCCFwMxcVbvKSme4LhncoaY3P30P+H4JIrACrZxHrEGsQdyAWISYRg4huxDFEG0Kb73cUpz44/JayFqv3EU+k6CJexD6O6SQN1pCFITi0XVmCVQ3iVTpuHsoYQryG+EVsLNhL0g+SoTeVQiBwGrEFoQB9p3MUIFoR7ya0pxvFSO4urDq4ny1E1vgU8fGCRPHlN5hZf0SsXODsUY0YQBxML83osAd/i23V4s4FV0Epew5eaEuVJA2aU4h/5kVwcBuL1i1Wg7NXe2DJukrIuX9TQru/uwmmO+phxpqsG7EX8dS8onjwdYWatkI2cCkSy3v5gKWKrjVWgQ+J2pSHCuvIGUdBMrBVyUfeT1LuZnCjxozkQkNdDGKhMlRW9h6OSudRTGAjQpWljGUbds4Ru9wFw9WrYOSTBxjoM22bLUzWOv1sGKhSVEcEiQ5lCDDD4mIPZN5WFIuhwASMfl4OkbH+eD99pm20jzk5yrryS0H2PkQe4l6nGiyRzTjrztK42FR7Pej+iSQZ2kb74sG0xmOnxRJHUYwzWiEbIMaUhkSoFswK7RPHyOR4WeHMxATcMqcWP5xd4pE6P+1LmIh1oLgURQEzyEw8KjNHFH0snsiQxC1llUkytM0tEAwNdNmZeMypic/SnZBZn7+3jfmYmpPL/t+++QDzy8CfsaTsvscDt66fyxxUNtjfZWnfqA69fIdEUltJCPyMv0/LXug73ZRAgj6L/42yNrsWb10v9Bi2cMQuzXyLCMpSg+/3ppR3BVTWIsVAJArf1J6LrWoCScWS4N2NZBwd94jMqamZI4IvykoQfY/KWgRHtO86fMktqRpI2uwHddyz6RAFnT0n4fr3u2wJTrbVg2w8xXQIml88Bv/ys4xIMq5FKcHiI+QSzrBeNvsJ/HjEK9ci7aMy0nSFLtTwN9Si6GJOMINDsTWxoMVqxFWZBsYa35EOvVJfZam9izfg8L4+oEk1C+GSmdmS4OomcgNnu12mhanOJvCfS97z0bbps3Lf84VhsLIDaKRlc3KiiVVHZ5KSZgwWHVpkUThaV5W4xE1PsDaZvKaBtv881HpnmJYWCeZVTTSopHSq80dwz0bQmU1WgfCVfhj7as7U11p2sTbZqvGbF747fJEd7EVSqslRVknpXKzQBRFL1zNQlqWyW4IMM7nCj2LH3cEPyqXvGglAX8Vx+CyiQ4DOmx/kfbymbUFEmC4us7cRqRCMJ9HuCnjbpcJuMznX8iJmXgqzEojC+OZOeO/8JIxzIiLJgEAwwgnScCKObrde6YAanL1pAg+N9kPUNyFLKaEv/oKdSG6Uk6JkZjjCnJQmxLnj6zemZvyA3nAJKnUdzji4USBHR2B3Qz+7TKIXS1PcrH5OMCSYVTfeOTgx8WytHlwLy0uXQbuqQJHdzC5Mwf4XOuAQ/7jGtTWLkKDBKK9FLZJUCYqRxSLupzK4b6UbWrEhT3rsDMHX60/Ah/G0H0NUIBoVoHEk3Nw4IagYXEM5+Sg8nOuCo/wQnhgUGvzw3K+wzRuM3w0SgaQm+Jz4LJrXMUEjSRbZnY/B4zmZ0MJXhFiyJnByRw9sar/KzCf6MRGI6AbSYCQ3nztq4wzJI8ehNaLBS/gvDLGoPdU8DBuRnI/7V1jwtbDBtEbNJV/KUQ1awe6GNp4jPfB8TzmcOPQgLBV2JpkcGQKMS5r1ZWiaBOGP8hjoh7auSvqwFMI4y/KfAAMADLPeID+rYAgAAAAASUVORK5CYII="
				, size: {
					width: 40
					, height: 40
				}
				, anchor: {
					width: 0
					, height: 0
				}
			}
			, pegman: {
				url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjhEQTQ3RTBFRTRFRTExRTRCMTg1Q0E3RjY3QUVBNkM4IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjhEQTQ3RTBGRTRFRTExRTRCMTg1Q0E3RjY3QUVBNkM4Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6OERBNDdFMENFNEVFMTFFNEIxODVDQTdGNjdBRUE2QzgiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6OERBNDdFMERFNEVFMTFFNEIxODVDQTdGNjdBRUE2QzgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5CMVzPAAAEf0lEQVR42sxYW28bRRQ+e/GlvjVt6rWtBEybkjhuERUQIQESTUObSiBeQIJniiIkkJBAICFA6gPwGF5aLqEv/AIQQiqgSlBzi2gFoi+taK40qRNC3NiuY2ez9vLN2puNY7tdG+82RxrN7Ow5u9985zKzy6mqSttZeNrmIppR4jiu4b2RkZG70L2K9jTaPdDk4JMZjL9G+3BsbOzvRrZmvMeZUmoAEOBecInF04d7k+6B6L8U8ueJqS5mdtCF2T30/V8ReU0RXgHIz2wHCHAngr7CmZcfv0wSgNWTpZtuOvVDnPUvAeSntgEEuCiYu/LW8CV3I3CbQX7wzf2MyRhATjcLsNUkeW0Qbr0dOCZgmY70JZ0Yvm5nFj/FYs6sDESXNBtbAMK9zCZqhj1dJH+BECR3w1a0g0FVC59mDMrKpYqttQAR6OwlUwsZj2kbVnZgNAvbol0x+NX4dNC08viMxLov7UyS0R8nwjfnV27P4vW0h85fDbOAHbUNIFyVXC/yL55OxOnaDW9DPbaAU+fjBN0TsJlv5V1NF2pkooDubbRn0CIir3Y+sm+RZ2UnHFjVdBaybKsL0i+ToZJS4pYx9Q/aObR3ATTbTKEWW1jUO/dKmZPPHpgir69ImYksKfkiqZNEyQ2VLD0ETA/3XOZ3xgLBQp4PfjfRfeC3mWAEN5+zjEGwxwYLJ5/8XdrFF8gB78pphVJ/ZuradcR85JacpIBY1cXTG18MqLIiBMHislVb3SFsXRIrvHpFc+4UNRBbxRkw5lUUF4dQov3BLFvgoJVJcrQ/slKuupsqmn+vhzi++kDh328kj64bC2m2Q1YCHI6HywBVxZgU4D5vdMfGtSfiIodPMHaSUrnvC6VZd8QSgIg/D8+pj/aWX6K5bbN4u90kuHniRI58e7fUxwrA7l058jqVXjyr2woGD+/bk3W5xWIVK0YiEQXgVuZuXqx2t67LZisLHLIC4NFYxb0sQVIFV42Ca7dDc2/NobXgNtwsNefmZgAei4fTG6eTn+cjpg0vLoQ2QqIvbAGDiJkuxE48uru8CRRkgcaTkmmAl5Y6KbPm0Mbsw6rDI3fhmb3tZHCYZaC+412YC9KaYn4TKpY4ujhnnH4qbh5qJ8Bj/Xr8QX6aDDVVm3BYoF+nDMb7Qu0H+IReoGdTPpq74dW+zuSiOfN1MJjMeJZmlv2bC/ZgOwE6ruPoxJIjcTXMrs+g5ZjrmpDPExMhUkq8tki2G7bt1wfk+Y8S/e85hdIDYO0Krj9Be3Or0h/XOikni/RYz2K9Z3w8Pi0dR+vBOMF+i7SNQZw+zqI9CHAduDyIcarR6TmZrnPKVjWmU7C7D30A/XG0b9vJoA40XZ2dbH3GnsfYW5VrH5lfF/SvQfYMxa7fb7KsVJuvNgBYb3F2AFytmbgFQEv/D5qV3Np2Bwhw+XWxpkjfMYCV4L+li5Vyrcy3+o7/s7wVlbgtDDqopHL5giLUJNSdAFjDJnaaHKt3LBa3RQyOnjuIjyW1ckYsF2PG7PtnD3Xp85Ui3bL8J8AAVVbQXdp1UEEAAAAASUVORK5CYII="
				, retina_url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjhEQTQ3RTBFRTRFRTExRTRCMTg1Q0E3RjY3QUVBNkM4IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjhEQTQ3RTBGRTRFRTExRTRCMTg1Q0E3RjY3QUVBNkM4Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6OERBNDdFMENFNEVFMTFFNEIxODVDQTdGNjdBRUE2QzgiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6OERBNDdFMERFNEVFMTFFNEIxODVDQTdGNjdBRUE2QzgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5CMVzPAAAEf0lEQVR42sxYW28bRRQ+e/GlvjVt6rWtBEybkjhuERUQIQESTUObSiBeQIJniiIkkJBAICFA6gPwGF5aLqEv/AIQQiqgSlBzi2gFoi+taK40qRNC3NiuY2ez9vLN2puNY7tdG+82RxrN7Ow5u9985zKzy6mqSttZeNrmIppR4jiu4b2RkZG70L2K9jTaPdDk4JMZjL9G+3BsbOzvRrZmvMeZUmoAEOBecInF04d7k+6B6L8U8ueJqS5mdtCF2T30/V8ReU0RXgHIz2wHCHAngr7CmZcfv0wSgNWTpZtuOvVDnPUvAeSntgEEuCiYu/LW8CV3I3CbQX7wzf2MyRhATjcLsNUkeW0Qbr0dOCZgmY70JZ0Yvm5nFj/FYs6sDESXNBtbAMK9zCZqhj1dJH+BECR3w1a0g0FVC59mDMrKpYqttQAR6OwlUwsZj2kbVnZgNAvbol0x+NX4dNC08viMxLov7UyS0R8nwjfnV27P4vW0h85fDbOAHbUNIFyVXC/yL55OxOnaDW9DPbaAU+fjBN0TsJlv5V1NF2pkooDubbRn0CIir3Y+sm+RZ2UnHFjVdBaybKsL0i+ToZJS4pYx9Q/aObR3ATTbTKEWW1jUO/dKmZPPHpgir69ImYksKfkiqZNEyQ2VLD0ETA/3XOZ3xgLBQp4PfjfRfeC3mWAEN5+zjEGwxwYLJ5/8XdrFF8gB78pphVJ/ZuradcR85JacpIBY1cXTG18MqLIiBMHislVb3SFsXRIrvHpFc+4UNRBbxRkw5lUUF4dQov3BLFvgoJVJcrQ/slKuupsqmn+vhzi++kDh328kj64bC2m2Q1YCHI6HywBVxZgU4D5vdMfGtSfiIodPMHaSUrnvC6VZd8QSgIg/D8+pj/aWX6K5bbN4u90kuHniRI58e7fUxwrA7l058jqVXjyr2woGD+/bk3W5xWIVK0YiEQXgVuZuXqx2t67LZisLHLIC4NFYxb0sQVIFV42Ca7dDc2/NobXgNtwsNefmZgAei4fTG6eTn+cjpg0vLoQ2QqIvbAGDiJkuxE48uru8CRRkgcaTkmmAl5Y6KbPm0Mbsw6rDI3fhmb3tZHCYZaC+412YC9KaYn4TKpY4ujhnnH4qbh5qJ8Bj/Xr8QX6aDDVVm3BYoF+nDMb7Qu0H+IReoGdTPpq74dW+zuSiOfN1MJjMeJZmlv2bC/ZgOwE6ruPoxJIjcTXMrs+g5ZjrmpDPExMhUkq8tki2G7bt1wfk+Y8S/e85hdIDYO0Krj9Be3Or0h/XOikni/RYz2K9Z3w8Pi0dR+vBOMF+i7SNQZw+zqI9CHAduDyIcarR6TmZrnPKVjWmU7C7D30A/XG0b9vJoA40XZ2dbH3GnsfYW5VrH5lfF/SvQfYMxa7fb7KsVJuvNgBYb3F2AFytmbgFQEv/D5qV3Np2Bwhw+XWxpkjfMYCV4L+li5Vyrcy3+o7/s7wVlbgtDDqopHL5giLUJNSdAFjDJnaaHKt3LBa3RQyOnjuIjyW1ckYsF2PG7PtnD3Xp85Ui3bL8J8AAVVbQXdp1UEEAAAAASUVORK5CYII="
				, size: {
					width: 40
					, height: 40
				}
				, anchor: {
					width: 0
					, height: 0
				}
			}
		};
    })();

    var markerIcon = function(options,asset_type){
        asset_type = asset_type || assets["marker"];
        if (!asset_type) return false;
        return new (L.Icon.Label.extend({
			options: {
				iconUrl: asset_type.url,
				iconRetinaUrl: asset_type.retina_url,
				shadowUrl: null,
				iconSize: new L.Point(asset_type.size.width, asset_type.size.height),
				iconAnchor: new L.Point(asset_type.anchor.width, asset_type.anchor.height),
				labelAnchor: new L.Point(asset_type.anchor.width, asset_type.anchor.height),
				wrapperAnchor: new L.Point(asset_type.size.width/2, asset_type.size.height),
				labelClassName: "marker-index-label"
			}
		}))(options);
    };

    var mapZoomHandler = function(e){
        this.zoom = this.map.getZoom();
    }

    var StreetViewService = (function(){
        if (!googlemaps_available) return {getPanoramaByLocation: function(){}};
        return new google.maps.StreetViewService();
    })();

    var StreetviewControl = (function(){
        var frankDragStart,frankDragEnd;

        return L.Control.extend({
			initialize: function (options) {
                L.Util.setOptions(this, options);
            },
			options: {
				position: "topright"
			},
			onAdd: function (map) {
                var container = L.DomUtil.create("div", "streetview-control");
                var toggle = L.DomUtil.create("div", "streetview-control-toggle", container);

                toggle.innerHTML = "<button>Streetview<i></i></button>";

                //L.DomEvent.addListener(toggle,"click",function(e){
                L.DomEvent.addListener(toggle,"mousedown",function(e) {
                    var self = this,
						mapper = this.options.mapper;
                    //if (this.options.mapper.streetview_available) this.options.mapper.toggleStreetView();

                    var timer = setTimeout(function() {
                        L.DomUtil.addClass(toggle,"pegman-active");
                        L.DomUtil.addClass(mapper.frank_dangling, "on");

                        if (mapper.frank) mapper.map.removeLayer(mapper.frank);

                        mapper.map.on("mousemove", function(e) {
                            var dragPos = e.containerPoint.add(L.point(-3, 5));
                            L.DomUtil.setPosition(mapper.frank_dangling, dragPos);
                        });
                    }, 500);

                    mapper.map.on("mouseup", function (e) {
                        if (L.DomUtil.hasClass(toggle, "pegman-active")) {
                            L.DomUtil.removeClass(toggle, "pegman-active");

                            mapper.frank.setLatLng(e.latlng);
                            mapper.map.addLayer(mapper.frank);

                            mapper.setStreetViewAvailable(function() {
                                mapper.toggleStreetView();
                            });
                        }

                        // reset everything.
                        clearTimeout(timer);
                        this.off("mouseup").off("mousemove");
                        L.DomUtil.removeClass(mapper.frank_dangling, "on");
                    });

                    if (e.stopPropagation) e.stopPropagation();
                    e.preventDefault();
                    return false;
                }.bind(this));

                frankDragStart = function(e){
                    L.DomUtil.setOpacity(toggle,0.3);
                };

                frankDragEnd = function(e){
                    var self = this;
                    this.setStreetViewAvailable(function(){
                        self.toggleStreetView();
                        L.DomUtil.setOpacity(toggle,1);
                    },function(){
                        L.DomUtil.setOpacity(toggle,0.3);
                    });
                }.bind(this.options.mapper);

                this.options.mapper.frank.on("dragstart",frankDragStart);
                this.options.mapper.frank.on("dragend",frankDragEnd);
                //return this.options.container
                return container;
            },
			onRemove: function(){
                this.options.mapper.frank.off("dragstart",frankDragStart);
                this.options.mapper.frank.off("dragend",frankDragEnd);
            }
		});
    })();

    var FullsizeControl = (function(){
        return L.Control.extend({
			initialize: function (options) {
                L.Util.setOptions(this, options);
            },
			options: {
				position: "topleft"
			},
			onAdd: function (map) {
                var container = L.DomUtil.create("div", "fullsize-control");
                var toggle = L.DomUtil.create("div", "fullsize-control-toggle",container);
                toggle.innerHTML = "<button>Fullsize<i></i></button>";
                L.DomEvent.addListener(toggle,"click",function(e){
                    this.options.mapper.toggleFullSize(!this.options.mapper.full_size);
                    if (e.stopPropagation) e.stopPropagation();
                    e.preventDefault();
                    return false;
                }.bind(this));

                return container;
            }
		});
    })();


    var LayersControl = (function(){
        return L.Control.extend({
			initialize: function (options) {
                L.Util.setOptions(this, options);
            },
			options: {
				position: "topright"
			},
			onAdd: function (map) {
                var container = L.DomUtil.create("ul", "layers-control");
                var buttons = this.options.mapper.providers.map(function(provider){
                    var toggle = L.DomUtil.create("li", "layers-control-toggle",container);
                    var button = L.DomUtil.create("button", "",toggle);
                    button.innerHTML = provider.name;
                    L.DomEvent.addListener(button,"click",function(e){
                        var center = this.options.mapper.map.getCenter();
                        this.options.mapper.center = [center.lat,center.lng];
                        this.options.mapper.setMap(provider);
                        if (e.stopPropagation) e.stopPropagation();
                        e.preventDefault();
                        return false;
                    }.bind(this));
                    return button;
                }.bind(this));

                return container;
            }
		});
    })();


    var Mapper = function(container,onMarkerClick){
        var _type = getType(container);
        $.extend(true,this,{
			container: _type==="html" ? container : arguments[0].container
			, center: (_type==="html" ? transform(container.getAttribute("map-locator")) : arguments[0].locator) || [0,0]
			, zoom: (_type==="html" ? transform(container.getAttribute("map-zoom")): arguments[0].zoom)||13
			, providers: (_type==="html" ? transform(container.getAttribute("map-providers")): arguments[0].providers) || ["OSM"]
			, markers_coords: (_type==="html" ? transform(container.getAttribute("map-markers")) : arguments[0].markers)||[]
			, streetview_active: (_type==="html" ? transform(container.getAttribute("map-streetview-active")) : arguments[0].streetview_active)||false
			, onMarkerClick: (arguments.length>1 ? arguments[1] : arguments[0].onMarkerClick)||function(){}
			, streetview_available: false
			, full_size: false
			, markers: []
		});
        this.frank = L.marker([0,0], {draggable: true, icon: L.icon({
			className: "map-pegman",
			iconUrl: assets.pegman.url
			, iconRetinaUrl: assets.pegman.retina_url
			, iconSize: new L.Point(assets.pegman.size.width, assets.pegman.size.height)
			, iconAnchor: new L.Point(assets.pegman.size.width / 2, assets.pegman.size.height)
		})});
        this.locator = L.marker(this.center,{draggable: false,icon: L.icon({
			className: "map-locator",
			iconUrl: assets.locator.url
			, iconRetinaUrl: assets.locator.retina_url
			, iconSize: new L.Point(assets.locator.size.width, assets.locator.size.height)
			, iconAnchor: new L.Point(assets.locator.size.width/2, assets.locator.size.height)
		})});

        this.providers = Object.keys(providers).filter(function(provider){
            return ~this.providers.indexOf(provider);
        }.bind(this)).map(function(provider){
            return providers[provider];
        });

        this.setMarkers.apply(this,this.markers_coords);
        this.setMap();
    };

    Mapper.prototype.setMap = function(provider){
        this.removeMap();
        this.setContainers();

        this.map = L.map(this.map_panel,{ zoomControl: false, worldCopyJump: true });
        this.toggleFullSize(this.full_size);
        this.setMapCenter();
        this.setMapBase(provider || this.providers[0]);
        //this.setStreetViewAvailable();
        this.map.addControl(new FullsizeControl({mapper: this}));
        if (this.streetview_active && googlemaps_available) this.map.addControl(new StreetviewControl({mapper: this}));
        this.map.addControl(L.control.scale());
        this.map.addControl(L.control.zoom({ position: "bottomright" }));
        if (this.providers.length>1)this.map.addControl(new LayersControl({mapper: this}));
        this.addMarkers();
        this.map.addLayer(this.locator);
        this.status = "map";
        return this;
    };

    Mapper.prototype.setContainers = function(){
        this.container.innerHTML = "";
        this.map_panel = L.DomUtil.create("div","map-panel panel-front",this.container);
        this.streetview_panel = L.DomUtil.create("div","streetview-panel",this.container);
        this.streetview_panel_container = L.DomUtil.create("div","streetview-panel-container",this.streetview_panel);
        this.frank_dangling = L.DomUtil.create("div","frank",this.container);
        this.close_panel = L.DomUtil.create("div","close-panel",this.container);
        this.close_panel.innerHTML = "X";
        L.DomEvent.addListener(this.close_panel,"click",function(e){
            //else if (this.full_size === true)  this.toggleFullSize(!this.full_size);
            if (this.status === "streetview") this.toggleStreetView();
        }.bind(this));
        return this;
    };

    Mapper.prototype.setLocator = function(pos){
        this.locator.setLatLng(pos);
        return this;
    };

    Mapper.prototype.setPegman = function(pos){
        this.frank.setLatLng(pos);
        this.setStreetViewAvailable();
        return this;
    };

    Mapper.prototype.fitToMarkers = function(markers){
        markers = arguments.length>0 ? Array.prototype.slice.call(arguments,0) : this.markers;

        this.map.fitBounds(L.featureGroup(markers).getBounds(), {pan: {animate: true}, zoom: {animate: true}});

        return this;
    };

    Mapper.prototype.setMapCenter = function(center,zoom){
        this.center = center || this.center;
        this.zoom = zoom || this.zoom;
        this.map.setView(this.center, this.zoom);
        this.map.off("zoomend",mapZoomHandler.bind(this)).on("zoomend",mapZoomHandler.bind(this));
        return this;
    };

    Mapper.prototype.setMapBase = function(provider){
        this.map.addLayer(provider.tiles());
        this.locator.remove();

        return this;
    };

    Mapper.prototype.removeMap = function(){
        if (this.map) this.map.remove();
        return this;
    };

    Mapper.prototype.setMarkers = function(){
        var _markers = Array.prototype.slice.call(arguments,0),_self = this;

        _markers.map(function(marker,index){
            if (getType(marker) === "object") {
                var identifier = marker.identifier ? marker.identifier : "";
                var count = (parseInt(marker.count) > 0) ? parseInt(marker.count) : 0;

                index = parseInt(Object.keys(marker)[0]);

                marker = marker[index];
                marker = L.marker(marker, {
					index: index,
					identifier: identifier,
					count: count,
					icon: markerIcon({labelText: index })
				});
            } else {
                marker = L.marker(marker);
            }
            marker.on("click",function(e){
                _self.onMarkerClick.call(_self,this,e);
            });
            return _self.markers.push(marker);
        });
        return this;
    };

    Mapper.prototype.addMarkers = function(markers){
        markers = arguments.length>0 ? Array.prototype.slice.call(arguments,0) : this.markers;
        markers.map(function(marker){
            this.map.addLayer(marker);
        }.bind(this));
        return this;
    };

    Mapper.prototype.setMarkerIcon = function(marker,asset_type){
        asset_type = assets[asset_type];
        if (asset_type) marker.setIcon(markerIcon({labelText: marker.options.icon.options.labelText},asset_type));
    };

    Mapper.prototype.removeMarkers = function(markers){
        markers = arguments.length>0 ? Array.prototype.slice.call(arguments,0) : this.markers;
        markers.map(function(marker){
            this.map.removeLayer(marker);
        }.bind(this));
        return this;
    };

    Mapper.prototype.setStreetViewAvailable = function(success,failed) {
        success = success || function(){};
        failed = failed || function(){};
        if (!googlemaps_available) return failed(false);
        var pos = this.frank.getLatLng();
        StreetViewService.getPanoramaByLocation(new google.maps.LatLng(pos.lat,pos.lng), 50, function(data, status){
            //console.log("data",data, status)
            this.streetview_available = status == google.maps.StreetViewStatus.OK;
            if (this.streetview_available) success(data, status);
			else failed(data, status);
        }.bind(this));
    };

    Mapper.prototype.toggleFullSize = function(full_size){
        if (!full_size){
            L.DomUtil.removeClass(this.map_panel,"full-size");
            L.DomUtil.removeClass(this.streetview_panel,"full-size");
            //L.DomUtil.removeClass(this.close_panel,"on");
            L.DomUtil.removeClass(this.close_panel,"full-size");
        }
		else {
            L.DomUtil.addClass(this.map_panel,"full-size");
            L.DomUtil.addClass(this.streetview_panel,"full-size");
            //L.DomUtil.addClass(this.close_panel,"on");
            L.DomUtil.addClass(this.close_panel,"full-size");
        }
        this.full_size = full_size;
        this.map.invalidateSize();
    };
    //TODO:add close when status==="map" and full_size ===true;
    Mapper.prototype.toggleStreetView = function(position){
        if (!googlemaps_available) return false;
        if (this.status === "streetview"){
            this.status = "map";
            L.DomUtil.addClass(this.map_panel,"panel-front");
            L.DomUtil.removeClass(this.streetview_panel,"panel-front");
            L.DomUtil.removeClass(this.close_panel,"on");
        } else {
            this.status = "streetview";
            var _self = this,
				_locator_pos = this.frank.getLatLng();

            position = position || [_locator_pos.lat,_locator_pos.lng];
            position = new google.maps.LatLng(position[0],position[1]);

            var panorama = new  google.maps.StreetViewPanorama(_self.streetview_panel_container, {position: position,pov: {heading: 34,pitch: 10}});
            L.DomUtil.removeClass(this.map_panel,"panel-front");
            L.DomUtil.addClass(this.streetview_panel,"panel-front");
            L.DomUtil.addClass(this.close_panel,"on");
            panorama.addListener("position_changed",function(){
                var pos = this.getPosition();
                _self.setMapCenter([pos.lat(),pos.lng()]);
                _self.setPegman([pos.lat(),pos.lng()]);
            });
        }
        return this;
    };

    return Mapper;
})(L,window.google);
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */
return Mapper;
});
}).apply(window);/**!!<[helper.leaflet-map]!!**/
/**!![helper.list]>!!**/
(function(){
registerHelper("list", function(application) {
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */

var $__Object$defineProperties = Object.defineProperties;

var List = function() {
    "use strict";

    function List(config) {
        this.collection = config.collection;
        this.scope = config.scope;
        this.Templates = {
            _items: config.items
        }
        this.init();
    }

    $__Object$defineProperties(List.prototype, {
        init: {
            value: function() {
                this.displayItems();
            },

            enumerable: false,
            writable: true
        },

        displayItems: {
            value: function() {
                $(this.scope).html(this.Templates._items(this.collection));
            },

            enumerable: false,
            writable: true
        }
    });

    return List;
}();

return List;
});
}).apply(window);/**!!<[helper.list]!!**/
/**!![helper.maps]>!!**/
(function(){
registerHelper("maps", function(application) {
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *  
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);  
 */

var $__Object$defineProperties = Object.defineProperties;

var Maps = function() {
    "use strict";

    function Maps(config) {
        this.config = config || {};
        this.Services = new app.services();
        this.map = this.Services.maps;

        $.ajax({
          url: "http://js.api.olp.yahooapis.jp/OpenLocalPlatform/V1/jsapi?appid=k649a2mxg65ALXQPvdsngZM9BKYBknXNeHaOsxXmk_cJz2XWeBDhl51LcF_35cK2",
          dataType: "script",
          cache: true
        }).done(function() {
            this.init();
        }.bind(this)).fail(function() {
            console.log("Failed to load Yahoo maps");
        });
    }

    $__Object$defineProperties(Maps.prototype, {
        init: {
            value: function() {
                this.map.startMap({
                    location: this.config.location,
                    zoom: this.config.zoom,
                    onPinClick: this.config.onPinClick,
                    labelCSS: this.config.labelCSS,
                    pinIcon: this.config.pinIcon,
              pinTemplate: this.config.pinTemplate,
              showPins: this.config.showPins,
              showLabels: this.config.showLabels,
              onMapMove: this.config.onMapMove,
              onMapZoom: this.config.onMapZoom
                });

                this.map.buildPins(this.config.collection);
            },

            enumerable: false,
            writable: true
        }
    });

    return Maps;
}();

return Maps;
});
}).apply(window);/**!!<[helper.maps]!!**/
/**!![helper.overlay]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_overlay"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"overlay-helper "
    + escapeExpression(((helper = (helper = helpers.center || (depth0 != null ? depth0.center : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"center","hash":{},"data":data}) : helper)))
    + "\">\n    \n    <div class=\"wrapper\">\n    <a class=\"close\" title=\"\" href=\"#\"></a>\n        <div class=\"container\">\n            <div class=\"res-1600-cols-12 res-1280-cols-12 res-1024-cols-12\">\n                <div class=\"content "
    + escapeExpression(((helper = (helper = helpers.moduleClass || (depth0 != null ? depth0.moduleClass : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"moduleClass","hash":{},"data":data}) : helper)))
    + "\"></div>\n            </div>\n        </div>\n    </div>\n</div>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.overlay.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("overlay", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var Overlay = function() {
    "use strict";

    function Overlay(config) {
        var Services = new app.services();

        this.Templates = {
            _overlay: Services.templateService.templates("helper.overlay._overlay")
        }

        this.config = config;
        this.altClass = this.config.overlayAltClass || null;
        this.moduleClass = this.config.moduleClass || "";
        this.pagetools = Services.pagetools;
        this.$window = this.pagetools.window._element;
        this._window = this.$window[0];
        this.$header = this.pagetools.header._element;
        this.$body = this.pagetools.body._element;

        setTimeout(function() {
            this.init.call(this);

            if (this.config.afterInit) {
                this.config.afterInit.apply(this, [this.$elContent]);
            }
        }.bind(this));
    }

    $__Object$defineProperties(Overlay.prototype, {
        init: {
            value: function(pagetools) {
                // Prevent new overlay from spawning if one is already open
                // TODO: Move to init when pagetools hack has been removed
                if ($("body").children(".overlay-helper").length) {
                    console.log("An overlay has already been spawned");

                    return;
                }

                // Add overlay markup
                var html = this.Templates._overlay({
                    moduleClass: this.altClass ? this.altClass : this.moduleClass,
                    center: this.config.center ? "center-vertically" : ""
                });

                this.pagetools.window.togglePageScroll();

                $("body").append(html);

                this.$element = $("body").children(".overlay-helper");
                this.$elContent = this.$element.find(".content");

                // Event bindings
                this.$element.find(".close").on("click", function(ev) {
                    ev.preventDefault();
                    this.close();
                }.bind(this));

                this.$element.on("click", function(ev) {
                    if($(ev.target).hasClass("overlay-helper") || $(ev.target).hasClass("wrapper")){
                        ev.preventDefault();
                        this.close();
                    }
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        close: {
            value: function() {
                // Fix for ie8 if we have an iframe in the overlay
                this.$element.find("iframe").hide();
                this.$element.remove();

                if (this.config.afterClose) {
                    this.config.afterClose.apply();
                }

                this.pagetools.window.togglePageScroll();
            },

            enumerable: false,
            writable: true
        }
    });

    return Overlay;
}();

return Overlay;
});
}).apply(window);/**!!<[helper.overlay]!!**/
/**!![helper.package-explorer]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_carousel"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "            <li>\n                <div class=\"content\">\n                    <div class=\"image res-1600-cols-6 res-1280-cols-6 res-1024-cols-6\">\n                        <img src=\""
    + escapeExpression(((helper = (helper = helpers.url || (depth0 != null ? depth0.url : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"url","hash":{},"data":data}) : helper)))
    + "\" alt=\"\" >    \n                    </div>            \n                    <div class=\"information res-1600-cols-6 res-1280-cols-6 res-1024-cols-6\">\n                        <h3>"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</h3>\n                        <p>ID: "
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "</p>\n                        <p class=\"description\">"
    + escapeExpression(((helper = (helper = helpers.description || (depth0 != null ? depth0.description : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"description","hash":{},"data":data}) : helper)))
    + "</p>\n                        <p class=\"price\">"
    + escapeExpression(((helper = (helper = helpers.totalPrice || (depth0 != null ? depth0.totalPrice : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"totalPrice","hash":{},"data":data}) : helper)))
    + " <span>取付費込価格（税込）</span></p>\n                        <a href=\"#\">詳細を見る</a>\n                    </div>\n                </div>\n            </li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "\n    <ul class=\"slides\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.options : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "    </ul>\n\n";
},"useData":true});
this["templates"]["_images"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"item\"><img src=\""
    + escapeExpression(((helper = (helper = helpers.mainImg || (depth0 != null ? depth0.mainImg : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"mainImg","hash":{},"data":data}) : helper)))
    + "\" alt=\"\" /></div>";
},"3":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "    <h2>"
    + escapeExpression(((helper = (helper = helpers.Title || (depth0 != null ? depth0.Title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"Title","hash":{},"data":data}) : helper)))
    + "</h2>\n";
},"5":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "		<li>\n            <a href=\"\" class=\"thumb\"><img src=\""
    + escapeExpression(((helper = (helper = helpers.ImageUrl || (depth0 != null ? depth0.ImageUrl : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"ImageUrl","hash":{},"data":data}) : helper)))
    + "\" alt=\"\"/></a>\n            <h3>"
    + escapeExpression(((helper = (helper = helpers.Header || (depth0 != null ? depth0.Header : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"Header","hash":{},"data":data}) : helper)))
    + "</h3>\n            <p>"
    + escapeExpression(((helper = (helper = helpers.Description || (depth0 != null ? depth0.Description : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"Description","hash":{},"data":data}) : helper)))
    + "</p>\n            <a href=\"\">"
    + escapeExpression(((helper = (helper = helpers.OverlayLinkText || (depth0 != null ? depth0.OverlayLinkText : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"OverlayLinkText","hash":{},"data":data}) : helper)))
    + "</a>\n        </li>                        	\n";
},"7":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "        <li><a href=\"\" class=\"thumb\"><img src=\""
    + escapeExpression(((helper = (helper = helpers.image || (depth0 != null ? depth0.image : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"image","hash":{},"data":data}) : helper)))
    + "\" alt=\"\"/></a></li>                         \n";
},"9":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "    <p class=\"price\">"
    + escapeExpression(((helper = (helper = helpers.Copy || (depth0 != null ? depth0.Copy : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"Copy","hash":{},"data":data}) : helper)))
    + "</p>\n";
},"11":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "    <div class=\"package-info\">\n        <div class=\"container\">\n            <div class=\"res-1024-cols-6 title\">\n                <h2>"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</h2>\n            </div>\n            <div class=\"res-1024-cols-6 price\">\n                <p>"
    + escapeExpression(((helper = (helper = helpers.totalPrice || (depth0 != null ? depth0.totalPrice : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"totalPrice","hash":{},"data":data}) : helper)))
    + " <span>(パッケージ合計価格)</span></p>\n            </div>\n        </div>      \n        <div class=\"container\">\n    		<p>"
    + escapeExpression(((helper = (helper = helpers.description || (depth0 != null ? depth0.description : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"description","hash":{},"data":data}) : helper)))
    + "</p>                                                   \n        </div>\n    </div>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.mainImg : depth0), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"if","hash":{},"fn":this.program(3, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "<ul class=\"item-nav wide-"
    + escapeExpression(((helper = (helper = helpers.imgsPerRow || (depth0 != null ? depth0.imgsPerRow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"imgsPerRow","hash":{},"data":data}) : helper)))
    + "\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(5, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.accessories : depth0), {"name":"each","hash":{},"fn":this.program(7, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "</ul>\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"if","hash":{},"fn":this.program(9, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.accessories : depth0), {"name":"if","hash":{},"fn":this.program(11, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"useData":true});
this["templates"]["_overlay"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"content\">    \n    <div class=\"image res-1600-cols-12 res-1280-cols-12 res-1024-cols-12\">\n        <img src=\""
    + escapeExpression(((helper = (helper = helpers.ImageUrl || (depth0 != null ? depth0.ImageUrl : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"ImageUrl","hash":{},"data":data}) : helper)))
    + "\" alt=\"\" >    \n    </div>            \n    <div class=\"information res-1600-cols-12 res-1280-cols-12 res-1024-cols-12\">\n        <h3>"
    + escapeExpression(((helper = (helper = helpers.Header || (depth0 != null ? depth0.Header : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"Header","hash":{},"data":data}) : helper)))
    + "</h3>\n        <p class=\"description\">"
    + escapeExpression(((helper = (helper = helpers.Description || (depth0 != null ? depth0.Description : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"Description","hash":{},"data":data}) : helper)))
    + "</p>\n        <a href=\"\">"
    + escapeExpression(((helper = (helper = helpers.OverlayLinkText || (depth0 != null ? depth0.OverlayLinkText : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"OverlayLinkText","hash":{},"data":data}) : helper)))
    + "</a>\n    </div>\n</div>";
},"useData":true});
this["templates"]["_tabs"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + " data-gallery-id=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\"><a class=\"button tab-select\" title=\""
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "\" href=\"#\">"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</a></li>\n";
},"2":function(depth0,helpers,partials,data) {
  return "class=\"selected\"";
  },"4":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + " data-gallery-id=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\"></li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<ul class=\"tab-helper helper-tabs level-1\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "</ul>\n<ul class=\"tab-helper helper-tabs level-2\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</ul>\n";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.package-explorer.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("package-explorer", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var PackageExplorer = function() {
    "use strict";

    function PackageExplorer(config) {
        var Services = new app.services(),
            templates = Services.templateService.templates;
        this.Helpers = new app.helpers();
        this.Templates = {
            _tabs: templates("helper.package-explorer._tabs"),
            _carousel: config.carousel,
            _overlay: config.overlay,
            _tabContent: config.tabContent
        };
        this.accessoryBaseUrl = (config.accessoryBaseUrl ? config.accessoryBaseUrl : null);
        this.overlayAltClass = (config.overlayAltClass ? config.overlayAltClass : null);
        this.collection = config.collection;
        this.view = config.scope;
        this.accessoryCarousel = (typeof config.accessoryCarousel !== "undefined") ? config.accessoryCarousel : false;
        this.tabsConfig = {
            scope: this.view,
            tabSelectMenu: this.view.find(".tab-select"),
            onTabInit: function(tabIndex, $tabContent) {
                this.tabInit(tabIndex, $tabContent);
            }.bind(this),
            onTabClick: function(tabIndex, $tabContent) {
                this.tabClick(tabIndex);
            }.bind(this)    
        }
        this.init();
    }

    $__Object$defineProperties(PackageExplorer.prototype, {
        init: {
            value: function(pagetools) {
                this.pagetools = pagetools;
                this.startTabs();
            },

            enumerable: false,
            writable: true
        },

        tabClick: {
            value: function(tabIndex) {
                this.tabIndex = tabIndex;
            },

            enumerable: false,
            writable: true
        },

        tabInit: {
            value: function(tabIndex, $tabContent) {
                var carData = this.collection.Items[tabIndex];
                var html = this.Templates._tabContent(carData);
                $tabContent.html(html);
                this.tabIndex = tabIndex;
            },

            enumerable: false,
            writable: true
        },

        startTabs: {
            value: function() {
                var carData = this.collection,
                    tabsTemplate = {"items": []};

                for (var i, i = 0; i < carData.Items.length; i++) {
                    var temp = {
                        title: carData.Items[i].Title,
                        id: carData.Items[i].id
                    };
                    tabsTemplate.items.push(temp);
                }
                // TODO - Use collection instead of custom template
                this.view.append(this.Templates._tabs(tabsTemplate));
                this.tabsConfig.tabSet = this.view.find(".tab-helper.level-1");
                this.tabsConfig.tabContentSet = this.view.find(".tab-helper.level-2");

                new (this.Helpers.tabs)(this.tabsConfig);

                this.bindThumbEvents();
            },

            enumerable: false,
            writable: true
        },

        startOverlay: {
            value: function(index) {
                var _this = this,
                    overlayConfig = {
                        // TODO Inigo - is there a reason for this line??
                        //moduleClass: typeof this.view[0].parentElement.className !== 'undefined' ? this.view[0].parentElement.className : this.view.selector,
                        moduleClass: _this.overlayAltClass ? _this.overlayAltClass : _this.view.attr("class") ,
                        afterInit: function (element) {
                            if (element) {
                                var $element = $(element);
                                var carouselConfig = {
                                    scope: $element,
                                    renderPagination: true
                                };
                                if(_this.accessoryCarousel) {
                                    var accessories = {"items": []},
                                        carouselData = _this.collection.Items[_this.tabIndex].Items[index];
                                    // loop through all the available accessory options 
                                    for (var i = 0; i < _this.collection.Accessories.length; i++) {
                                        // loop through the options available to the current accessory
                                        for(var j = 0; j < carouselData.AccessoryIds.length; j++) {
                                            // filter the options so only the available ones are pushed to the template (via IDs)
                                            if(_this.collection.Accessories[i].AccessoryId === carouselData.AccessoryIds[j]) {
                                                accessories.items.push(_this.collection.Accessories[i]);
                                            }
                                        }
                                    }

                                    if(_this.accessoryBaseUrl) {
                                        accessories.url = _this.accessoryBaseUrl;
                                    }

                                    $element.html(_this.Templates._carousel(accessories));
                                    _this.carouselHelper = new (_this.Helpers.carousel)(carouselConfig);
                                } else {
                                    var overlayData = _this.collection.Items[_this.tabIndex].Items[index],
                                        overlayTemplate = _this.Templates._overlay(overlayData);
                                    $element.html(overlayTemplate);
                                }
                            }
                        }
                    };
                new (this.Helpers.overlay)(overlayConfig);
            },

            enumerable: false,
            writable: true
        },

        bindThumbEvents: {
            value: function() {
                this.view.off("click", ".item-nav a");
                var _this = this;
                this.view.on("click", ".item-nav a", function (event) {
                    event.preventDefault();
                    _this.startOverlay($(this).closest("li").index());
                });
            },

            enumerable: false,
            writable: true
        },

        bindMobileTabsEvents: {
            value: function() {
                this.view.off("click");

                var _this = this;
                this.view.find(".tab-select").on("click", function (event) {
                    event.preventDefault();
                    $(this).toggleClass("opened");
                    _this.view.find(".tab-helper.level-1").toggleClass("mobile-visible");
                });
            },

            enumerable: false,
            writable: true
        },

        setSelectedMobileTab: {
            value: function(scope) {
                var selectedTabText = scope ? scope.text() : this.tabsConfig.tabSet.find(".selected").children().text();
                this.tabsConfig.tabSelectMenu.text(selectedTabText);
            },

            enumerable: false,
            writable: true
        }
    });

    return PackageExplorer;
}();

return PackageExplorer;
});
}).apply(window);/**!!<[helper.package-explorer]!!**/
/**!![helper.related-videos]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_related_videos"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, buffer = "     <p class=\"related-articles-title\">関連記事</p>\n      <ul class=\"related-articles\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.relatedArticles : depth0), {"name":"each","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "      </ul>\n";
},"2":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "           <li>\n             <a href=\""
    + escapeExpression(((helper = (helper = helpers.articleUrl || (depth0 != null ? depth0.articleUrl : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"articleUrl","hash":{},"data":data}) : helper)))
    + "\" target=\""
    + escapeExpression(((helper = (helper = helpers.target || (depth0 != null ? depth0.target : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"target","hash":{},"data":data}) : helper)))
    + "\">\n                <div class=\"img\" style=\"background-image: url("
    + escapeExpression(((helper = (helper = helpers.imageUrl || (depth0 != null ? depth0.imageUrl : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"imageUrl","hash":{},"data":data}) : helper)))
    + ")\">\n                 </div>\n                <p class=\"cta-text\"> ";
  stack1 = ((helper = (helper = helpers.ctaText || (depth0 != null ? depth0.ctaText : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"ctaText","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  return buffer + " </p>\n             </a>\n           </li>\n";
},"4":function(depth0,helpers,partials,data) {
  var stack1, buffer = "      <p class=\"related-videos-title\">関連動画</p>\n      <ul class=\"related-videos\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.relatedVideos : depth0), {"name":"each","hash":{},"fn":this.program(5, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "      </ul>\n";
},"5":function(depth0,helpers,partials,data) {
  var stack1, helper, lambda=this.lambda, escapeExpression=this.escapeExpression, functionType="function", helperMissing=helpers.helperMissing, buffer = "           <li class='index-"
    + escapeExpression(lambda((data && data.index), depth0))
    + " rel-video' data-yt-id=\""
    + escapeExpression(((helper = (helper = helpers.youtubeId || (depth0 != null ? depth0.youtubeId : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"youtubeId","hash":{},"data":data}) : helper)))
    + "\" data-vl=\""
    + escapeExpression(((helper = (helper = helpers.vlid || (depth0 != null ? depth0.vlid : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"vlid","hash":{},"data":data}) : helper)))
    + "\">\n             <div class=\"img\" style=\"background-image: url(https://img.youtube.com/vi/"
    + escapeExpression(((helper = (helper = helpers.youtubeId || (depth0 != null ? depth0.youtubeId : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"youtubeId","hash":{},"data":data}) : helper)))
    + "/default.jpg)\">\n               <span class=\"play-icon\"> </span>\n             </div>\n             <p class=\"cta-text\"> ";
  stack1 = ((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  return buffer + " </p>\n           </li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"related-video-wrapper\">\n\n  <div class=\"res-1024-cols-8\">\n    <div class=\"iframe-wrapper\">\n      <div class=\"main-video-container\"></div>\n    </div>\n    <p class=\"title\">  </p>\n  </div>\n\n  <div class=\"res-1024-cols-4\">\n\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.relatedArticles : depth0), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.relatedVideos : depth0), {"name":"if","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n  </div>\n\n</div>";
},"useData":true});
this["templates"]["_single_video"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<div class=\"related-video-wrapper single\">\n\n  <div class=\"res-1024-cols-12\">\n    <div class=\"single-video-wrapper\">\n      <div class=\"main-video-container\"></div>\n    </div>    \n    <p class=\"title\"> "
    + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.relatedVideos : depth0)) != null ? stack1['0'] : stack1)) != null ? stack1.title : stack1), depth0))
    + "</p>\n  </div>\n\n</div>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.related-videos.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("related-videos", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var RelatedVideosHelper = function() {
  "use strict";

  function RelatedVideosHelper(config) {
    this.Services = new app.services();
    this.Helpers = new app.helpers();
    this.config = config;
    this.pagetools = this.Services.pagetools;
    this.window = this.pagetools.window;
    this.$html = $(this.pagetools.window._element[0].document).find("html");
    this.$body = this.pagetools.body._element;

    this.Templates = {
      _single_video: this.config.templates && this.config.templates._single_video ? this.config.templates._single_video : this.Services.templateService.templates("helper.related-videos._single_video"),
      _related_videos: this.config.templates && this.config.templates._related_videos ? this.config.templates._related_videos : this.Services.templateService.templates("helper.related-videos._related_videos")
    }

    this.currentYoutubeId = this.config.mainVideo;

    this.overlayConfig = {
      moduleClass: "related-video-overlay",
      center: false,
      afterInit: function(element) {
        if (element) this.onOverlayStart(element);
      }.bind(this)
    };

    this.init.call(this);
  }

  $__Object$defineProperties(RelatedVideosHelper.prototype, {
    replaceVideo: {
      value: function(id, title) {
        this.playerInstance.cueVideoById(id);
        this.currentYoutubeId = id;
        this._overlay.find("p.title").html(title);
      },

      enumerable: false,
      writable: true
    },

    bindVideoEvents: {
      value: function(element) {
        var self = this;
        $(".rel-video").on("click", function() {
          var clickedYtId = $(this).data("yt-id"),
            newTitle = $(this).find(".cta-text").html();
          if (self.currentYoutubeId !== clickedYtId) {
            $(".rel-video").removeClass("selected");
            $(this).addClass("selected");
            if (typeof VL_Send !== "undefined") VL_Send($(this).data("vl"));
            self.replaceVideo(clickedYtId, newTitle);
            if (self.pagetools.window.isMobile()) {
              $(element.closest(".wrapper")).scrollTop(0);
            }
          }
        });
      },

      enumerable: false,
      writable: true
    },

    appendTemplate: {
      value: function() {
        this._overlay.append(this.template);
      },

      enumerable: false,
      writable: true
    },

    onOverlayStart: {
      value: function(element) {
        var self = this;
        this._overlay = element;
        this.appendTemplate();
        this.Services.youtubeIframeApi
          .then(function(YT) {
          return YT.createPlayer(element.find(".main-video-container")[0], self.config.mainVideo);
        }).then(function(player) {
          self.playerInstance = player;
          self.bindVideoEvents(element);
        }.bind(this))["catch"](function(err) {
          throw new Error(err);
        });
      },

      enumerable: false,
      writable: true
    },

    getTemplate: {
      value: function() {
        // main video and (  related article or related videos  )
        if (this.config.mainVideo && (this.config.relatedArticles.length || this.config.relatedVideos.length)){
          return this.Templates._related_videos(this.config);
        }

        // only main video 
        else if (this.config.mainVideo && !this.config.relatedArticles.length && !this.config.relatedVideos.length){
          return this.Templates._single_video(this.config);
        }

        else {
          console.info("Not existing scenario");
        }
      },

      enumerable: false,
      writable: true
    },

    init: {
      value: function() {
        this.template = this.getTemplate();
        this.overlayHelper = new(this.Helpers["overlay"])(this.overlayConfig);
      },

      enumerable: false,
      writable: true
    }
  });

  return RelatedVideosHelper;
}();

return RelatedVideosHelper;
});
}).apply(window);/**!!<[helper.related-videos]!!**/
/**!![helper.tabs]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_tabs-dropdown"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += ">";
  stack1 = ((helper = (helper = helpers.content || (depth0 != null ? depth0.content : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"content","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</li>\n";
},"2":function(depth0,helpers,partials,data) {
  return "class=\"selected\"";
  },"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"tab-is-dropdown\"></div>\n<ul class=\"helper-tabs level-2\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</ul>";
},"useData":true});
this["templates"]["_tabs-not-nested"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "><a title=\""
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "\" href=\"#\">"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</a></li>\n";
},"2":function(depth0,helpers,partials,data) {
  return "class=\"selected\"";
  },"4":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += ">";
  stack1 = ((helper = (helper = helpers.content || (depth0 != null ? depth0.content : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"content","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<ul class=\"helper-tabs level-1\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "</ul>\n<ul class=\"helper-tabs level-2\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</ul>";
},"useData":true});
this["templates"]["_tabs"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "><a title=\""
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "\" href=\"#\"><span>"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</span></a>\n        <ul class=\"helper-tabs level-2\">\n            <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += ">";
  stack1 = ((helper = (helper = helpers.content || (depth0 != null ? depth0.content : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"content","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</li>\n        </ul>\n    </li>\n";
},"2":function(depth0,helpers,partials,data) {
  return "class=\"selected\"";
  },"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<ul class=\"helper-tabs level-1\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</ul>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('helper.tabs.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerHelper("tabs", function(application) {
/**
 * @class Tabs
 * @classdesc Renders html elements as tabs, with a given collection or existent markup.
 * Turns tabs into a dropdown on mobile as default, using the Dropdown Helper.
 */
var $__Object$defineProperties = Object.defineProperties;

var Tabs = function() {
    "use strict";

    function Tabs(config) {
        var Services = new app.services(),
            tabsTemplate = null,
            defaultConfig = {
                mobileAsDropdown: true,
                onResize: true
            };

        this.config = $.extend(defaultConfig, config);
        this.isDropdown = false;
        this.$window = $(window);

        tabsTemplate = this.config.tabsNotNested ? "_tabs-not-nested" : "_tabs";
        this.Templates = {
            _tabs: Services.templateService.templates("helper.tabs." + tabsTemplate),
            _dropdown: Services.templateService.templates("helper.tabs._tabs-dropdown")
        };

        this.Helpers = new app.helpers();

        if (this.config.beforeInit) {
            this.config.beforeInit.apply();
        }

        setTimeout(function() {
            this.pagetools = Services.pagetools;
            this.isMobile = this.pagetools.window.isMobile();
            this.init();

            if (this.config.afterInit) {
                this.config.afterInit.apply();
            }
        }.bind(this));
    }

    $__Object$defineProperties(Tabs.prototype, {
        init: {
            value: function() {
                // Switch for template renderer
                if (this.config.tabSet) {
                    // Use existing markup
                    // Add helper class
                    this.$configTabSet = $(this.config.tabSet);
                    this.$configTabContentSet = $(this.config.tabContentSet);
                    this.wrapHelper();
                    this.$configTabSet.addClass("helper-tabs");
                    this.$configTabContentSet.addClass("helper-tabs");

                    this.$tabSet = this.$configTabSet.children("li");
                    this.$tabContentSet = this.$configTabContentSet.children("li");
                    this.config.tabCollection = [];

                    if (this.config.hideSingularTab) {
                        // Hide the tab headings
                        //this.$configTabSet.hide();
                        //this.$tabSet.hide();
                        this.$tabSet.parent("ul").hide();
                    } else {
                        // If mobile is dropdown
                        // Only start dropdown if tabs are at least more than 1
                        if (this.config.mobileAsDropdown && this.$tabSet.length > 1) {
                            this.setDropdownCollection();
                            this.mobileAsDropdown();
                        } else {
                            this.bindEvents();
                        }
                    }
                } else if (this.config.tabCollection && this.config.tabCollection.length > 0) {
                    // Render template
                    this.$scope = $(this.config.scope);
                    // Only start dropdown if tabs are at least more than 1
                    if (this.config.mobileAsDropdown && this.config.tabCollection.length > 1) {
                        this.mobileAsDropdown();
                    } else {
                        this.startTabs();

                        if (this.config.hideSingularTab) {
                            // Hide the tab headings
                            //this.$configTabSet.hide();
                            //this.$tabSet.hide();
                            this.$tabSet.parent("ul").hide();
                        }
                    }
                } else {
                    console.log("Nothing to do!");
                    return;
                }
            },

            enumerable: false,
            writable: true
        },

        mobileAsDropdown: {
            value: function() {
                if (this.isMobile) {
                    // Cache desktop tabs before replacing with dropdown
                    this.cacheTabs();
                    this.startDropdown();
                } else {
                    this.startTabs();
                }
                if (this.config.onResize) {
                    this.resizeEvents();
                }
            },

            enumerable: false,
            writable: true
        },

        setDropdownCollection: {
            value: function() {
                if (!!this.$tabSet && this.config.tabSet) {
                    var temp;
                    for (var i = 0; i < this.$tabSet.length; i++) {
                        temp = {};
                        temp.title = $(this.$tabSet[i]).text();
                        temp.content = $(this.$tabContentSet[i]).html();
                        this.config.tabCollection.push(temp);
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        startTabs: {
            value: function() {
                if (!this.config.tabSet) {
                    var html = this.Templates._tabs({
                            items: this.config.tabCollection
                        });
                    this.renderHtml(html);
                } else if (this.cachedTabs) {
                    this.replaceTabSet(this.tabHtml);
                    this.$tabSet = this.$tabsWrapper.children().first().children("li");
                } else {
                    this.cacheTabs();
                }
                this.isDropdown = false;
                this.bindEvents();
            },

            enumerable: false,
            writable: true
        },

        startDropdown: {
            value: function() {
                var tabIsSet = !!this.config.tabSet,
                    html,
                    dropdownScope;

                // Generate collection for dropdown from the config collection
                if (!this.dropdownCollection) {
                    this.dropdownCollection = this.cloneCollection(this.config.tabCollection);
                    for (var i = 0; i < this.dropdownCollection.length; i++ ) {
                        this.dropdownCollection[i].content = this.dropdownCollection[i].title;
                        this.dropdownCollection[i].url = "#";
                    }
                }
                if (tabIsSet) {
                    var $dropdownWrapper = $("<div class=\"tab-is-dropdown\" />");
                    this.replaceTabSet($dropdownWrapper);
                    dropdownScope = $dropdownWrapper;
                } else {
                    html = this.Templates._dropdown({
                        items: this.config.tabCollection
                    });
                    this.renderHtml(html);
                    dropdownScope = this.$scope.find(".tab-is-dropdown");
                }

                this.isDropdown = true;

                var dropdownConfig = {
                    scope: dropdownScope,
                    collection: this.dropdownCollection,
                    preventDefault: true,
                    defaultDropownIndex: this.config.defaultTabIndex || 0,
                    optionClick: function($currentTarget, $dropdown, $dropdownContent) {
                        var tabIndex = $currentTarget.parent("li").index(),
                            $tab = $(this.$tabSet.get(tabIndex)),
                            $tabContent = $(this.$tabContentSet.get(tabIndex));

                        this.toggleTab($tab, $tabContent);
                        this.processTab(tabIndex, $tabContent, $tabContent, false);
                    }.bind(this),
                    afterInit: function() {
                        this.defaultTab(true);
                    }.bind(this)
                };

                if (this.dropdownCollection && !!this.dropdownCollection.length) {
                    this.dropdownTabs = new this.Helpers["drop-down"](dropdownConfig);
                }
            },

            enumerable: false,
            writable: true
        },

        renderHtml: {
            value: function(html) {
                if (html) {
                    this.resetTabs();
                    this.wrapHelper();
                    this.$scope.append(html);
                    //debugger;
                    this.$tabSet = this.$scope.find(".helper-tabs.level-1 > li");
                    this.$tabContentSet = this.$scope.find(".helper-tabs.level-2 > li");
                } else if (this.cachedTabs) {
                    this.$scope.append(this.tabHtml).append(this.tabContentHtml);
                }
            },

            enumerable: false,
            writable: true
        },

        wrapHelper: {
            value: function() {
                this.$tabsWrapper = $("<div class=\"helper-tabs-wrapper\"/>");
                if (this.config.tabSet) {
                    this.$configTabSet.before(this.$tabsWrapper);
                    this.$tabsWrapper.append(this.$configTabSet);
                    this.$tabsWrapper.append(this.$configTabContentSet);
                } else {
                    if (!this.$scope.is(".helper-tabs-wrapper")) {
                        this.$scope.append(this.$tabsWrapper);
                        this.$scope = this.$tabsWrapper;
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        replaceTabSet: {
            value: function(html) {
                this.$tabsWrapper.children().first().replaceWith(html);
            },

            enumerable: false,
            writable: true
        },

        defaultTab: {
            value: function(dropdown) {
                var defaultTabIndex = this.config.defaultTabIndex || 0,
                    $tab = $(this.$tabSet.get(defaultTabIndex)),
                    $tabContent = $(this.$tabContentSet.get(defaultTabIndex));

                if (defaultTabIndex >= 0) {
                    this.toggleTab($tab, $tabContent);
                }
                if (dropdown) {
                    $tab = $tabContent;
                }

                this.processTab(
                    defaultTabIndex,
                    $tab,
                    $tabContent,
                    true,
                    null
                );
            },

            enumerable: false,
            writable: true
        },

        bindEvents: {
            value: function() {
                if(!this.config.tabsHover) {
                    this.$tabSet.children("a").on("click", function(e) {
                        e.preventDefault();

                        var tabIndex = $(e.currentTarget).parent("li").index(),
                            $tab = $(this.$tabSet.get(tabIndex)),
                            $tabContent = $(this.$tabContentSet.get(tabIndex));

                        this.toggleTab($tab, $tabContent);
                        this.processTab(tabIndex, $tab, $tabContent, false, e);
                    }.bind(this));
                } else {
                    this.$tabSet.children("a").on("click mouseenter", function(e) {
                        e.preventDefault();

                        // TODO: -1 is a quick fix for TOP link throwing categories out of whack.
                        var tabIndex = $(e.currentTarget).parent("li").index() -1,
                            $tab = $(this.$tabSet.get(tabIndex)),
                            $tabContent = $(this.$tabContentSet.get(tabIndex));

                        this.toggleTab($tab, $tabContent);
                        this.processTab(tabIndex, $tab, $tabContent, false, e);
                    }.bind(this));
                }

                this.defaultTab();
            },

            enumerable: false,
            writable: true
        },

        resizeEvents: {
            value: function() {
                this.$window.on("resize.helperTabs", function() {
                    this.isMobile = this.pagetools.window.isMobile();
                    if (this.isMobile && !this.isDropdown) {
                        this.startDropdown();
                    }
                    if (!this.isMobile && this.isDropdown) {
                        this.startTabs();
                    }
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        toggleTab: {
            value: function($tab, $tabContent) {
                // Remove .selected from the currently selected item
                this.$tabSet.filter(".selected").removeClass("selected");
                this.$tabContentSet.filter(".selected").removeClass("selected");

                // Change the clicked item to .selected
                $tab.addClass("selected");
                $tabContent.addClass("selected");
            },

            enumerable: false,
            writable: true
        },

        processTab: {
            value: function(tabIndex, $tab, $tabContent, automatedInput, e) {
                var ev = e || null;

                if (!$tab.attr("data-processed")) {
                    if (!automatedInput && this.config.onFirstTabClick) {
                        this.config.onFirstTabClick.apply(this, [
                            tabIndex, $tabContent, ev
                        ]);
                    }

                    if (this.config.onTabInit) {
                        this.config.onTabInit.apply(this, [
                            tabIndex, $tabContent, ev
                        ]);
                    }

                    $tab.attr("data-processed", "true");
                }

                if (!automatedInput && this.config.onTabClick) {
                    this.config.onTabClick.apply(this, [
                        tabIndex, $tabContent
                    ]);
                }
            },

            enumerable: false,
            writable: true
        },

        cacheTabs: {
            value: function() {
                if (this.$tabSet) {
                    this.tabHtml = this.$tabSet.parent()[0].outerHTML;
                    this.tabContentHtml = this.$tabContentSet.parent()[0].outerHTML;
                    this.cachedTabs = true;
                }
            },

            enumerable: false,
            writable: true
        },

        resetTabs: {
            value: function() {
                this.$scope.empty();
            },

            enumerable: false,
            writable: true
        },

        cloneCollection: {
            value: function(collection) {
                return JSON.parse(JSON.stringify(collection));
            },

            enumerable: false,
            writable: true
        }
    });

    return Tabs;
}();

return Tabs;
});
}).apply(window);/**!!<[helper.tabs]!!**/
/**!![service.api]>!!**/
(function(){
registerService("api", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var Api = function() {
    "use strict";

    function Api() {
        this.cache = {};
        this.apis = {};

        // for local testing
        //window.MDPConfig.apiServices = [{"Name":"GetCarShowcase","Url":"api/carshowcase/get?id={id}","Queryable":["id"],"Action":"GET"},{"Name":"GetCarShowcase","Url":"api/{lang}/carshowcase/get?id={id}","Queryable":["id","lang"],"Action":"GET"},{"Name":"GetCarShowcase","Url":"api/carshowcaseca/get?id={id}","Queryable":["id"],"Action":"GET"},{"Name":"GetCarShowcase","Url":"api/{lang}/carshowcaseca/get?id={id}","Queryable":["id","lang"],"Action":"GET"},{"Name":"ReadAllData","Url":"api/leads/data","Queryable":[],"Action":"GET"},{"Name":"GetByIds","Url":"api/accessorycms/get?accessoryBlockId={accessoryBlockId}&modelName={modelName}&page={page}","Queryable":["accessoryBlockId","modelName","page"],"Action":"GET"},{"Name":"Filter","Url":"api/accessorycms/filter?page={page}","Queryable":["page"],"Action":"GET"},{"Name":"GetHighLightedFaqData","Url":"api/faqdata/GetFaqBlockData/{id}?lang={lang}","Queryable":["id","lang"],"Action":"GET"},{"Name":"GetHighLightedFaqData","Url":"api/{lang}/faqdata/GetFaqBlockData/{id}","Queryable":["id","lang"],"Action":"GET"},{"Name":"GetFaqData","Url":"api/faqdata/GetFaqData/{id}?lang={lang}","Queryable":["id","lang"],"Action":"GET"},{"Name":"GetFaqData","Url":"api/{lang}/faqdata/GetFaqData/{id}","Queryable":["id","lang"],"Action":"GET"},{"Name":"GetResults","Url":"api/cars/specs","Queryable":["inputs"],"Action":"POST"},{"Name":"GetCarModelData","Url":"api/{lang}/cars/models?showGrades={showGrades}&showSpecs={showSpecs}","Queryable":["showGrades","showSpecs","lang"],"Action":"GET"},{"Name":"GetCarModelData","Url":"api/cars/models?showGrades={showGrades}&showSpecs={showSpecs}&lang={lang}","Queryable":["showGrades","showSpecs","lang"],"Action":"GET"},{"Name":"GetCarModelDataByCarId","Url":"api/{lang}/cars/model?carId={carId}&showGrades={showGrades}&showSpecs={showSpecs}","Queryable":["carId","showGrades","showSpecs","lang"],"Action":"GET"},{"Name":"GetCarModelDataByCarId","Url":"api/cars/model?carId={carId}&showGrades={showGrades}&showSpecs={showSpecs}&lang={lang}","Queryable":["carId","showGrades","showSpecs","lang"],"Action":"GET"},{"Name":"GetModelByShowroomId","Url":"api/cardata/model?id={id}","Queryable":["id"],"Action":"GET"},{"Name":"GetModelListByShowroomListId","Url":"api/cardata/modellist?id={id}","Queryable":["id"],"Action":"GET"},{"Name":"GetCarsByPrefecture","Url":"api/carsearch/prefectures?prefecture={prefecture}&carId={carId}&engine={engine}&transmission={transmission}&grade={grade}&drive={drive}&fuel={fuel}&dealer={dealer}&groupDealers={groupDealers}&page={page}","Queryable":["prefecture","carId","engine","transmission","grade","drive","fuel","dealer","groupDealers","page"],"Action":"GET"},{"Name":"GetCarsByDealerKeyword","Url":"api/carsearch/keyword?searchTerm={searchTerm}&carId={carId}&engine={engine}&transmission={transmission}&grade={grade}&drive={drive}&fuel={fuel}&dealer={dealer}&page={page}","Queryable":["searchTerm","carId","engine","transmission","grade","drive","fuel","dealer","page"],"Action":"GET"},{"Name":"GetCarsByLocation","Url":"api/carsearch/location?latitude={latitude}&longitude={longitude}&carId={carId}&engine={engine}&transmission={transmission}&grade={grade}&drive={drive}&fuel={fuel}&dealer={dealer}&page={page}","Queryable":["latitude","longitude","carId","engine","transmission","grade","drive","fuel","dealer","page"],"Action":"GET"},{"Name":"SubmitData","Url":"api/forms/submit","Queryable":["formData"],"Action":"POST"},{"Name":"GetModelListByAccessoryIds","Url":"api/accessorydata/modellist?accessoryId={accessoryId}","Queryable":["accessoryId"],"Action":"GET"},{"Name":"GetByModelName","Url":"api/accessorydata/getbymodelname?modelName={modelName}","Queryable":["modelName"],"Action":"GET"},{"Name":"GetAccessoryListByBodyTypeModel","Url":"api/accessorydata/bodytypemodel?id={id}","Queryable":["id"],"Action":"GET"},{"Name":"GetAccessoryById","Url":"api/accessorydata/get?id={id}","Queryable":["id"],"Action":"GET"},{"Name":"GetAccessoryListByShowroomId","Url":"api/accessorydata/model?id={id}","Queryable":["id"],"Action":"GET"},{"Name":"GetAccessoryList","Url":"api/accessorydata/list","Queryable":[],"Action":"GET"},{"Name":"GetDealer","Url":"api/dealersearch/dealer?dealerId={dealerId}&shopId={shopId}&lang={lang}","Queryable":["dealerId","shopId","lang"],"Action":"GET"},{"Name":"GetDealer","Url":"api/{lang}/dealersearch/dealer?dealerId={dealerId}&shopId={shopId}","Queryable":["dealerId","shopId","lang"],"Action":"GET"},{"Name":"SearchDealers","Url":"api/{lang}/dealersearch/query/keywords?searchTerm={searchTerm}&page={page}","Queryable":["searchTerm","page","lang"],"Action":"GET"},{"Name":"SearchDealers","Url":"api/dealersearch/query/keywords?searchTerm={searchTerm}&page={page}&lang={lang}","Queryable":["searchTerm","page","lang"],"Action":"GET"},{"Name":"GetDealersByCoordinates","Url":"api/dealersearch/query/location?latitude={latitude}&longitude={longitude}&page={page}&lang={lang}","Queryable":["latitude","longitude","page","lang"],"Action":"GET"},{"Name":"GetDealersByCoordinates","Url":"api/{lang}/dealersearch/query/location?latitude={latitude}&longitude={longitude}&page={page}","Queryable":["latitude","longitude","page","lang"],"Action":"GET"},{"Name":"GetDealersByPostCode","Url":"api/{lang}/dealersearch/query/postcode?postcode={postcode}&page={page}&dealer={dealer}&groupDealers={groupDealers}","Queryable":["postcode","page","dealer","groupDealers","lang"],"Action":"GET"},{"Name":"GetDealersByPostCode","Url":"api/dealersearch/query/postcode?postcode={postcode}&page={page}&dealer={dealer}&groupDealers={groupDealers}&lang={lang}","Queryable":["postcode","page","dealer","groupDealers","lang"],"Action":"GET"},{"Name":"GetDealerCalendar","Url":"api/dealersearch/query/calendar?dealerId={dealerId}&shopId={shopId}&page={page}","Queryable":["dealerId","shopId","page"],"Action":"GET"},{"Name":"GetPrefectureList","Url":"api/dealersearch/list/prefectures?carId={carId}","Queryable":["carId"],"Action":"GET"},{"Name":"GetSocialMediaFeed","Url":"api/socialfeeddata/{id}?lang={lang}","Queryable":["id","lang"],"Action":"GET"},{"Name":"GetSocialMediaFeedItem","Url":"api/socialfeeditemdata/{id}?lang={lang}","Queryable":["id","lang"],"Action":"GET"},{"Name":"GetGradeSpec","Url":"api/gradespec/get?gradeId={gradeId}","Queryable":["gradeId"],"Action":"GET"},{"Name":"GetView360","Url":"api/view360/get?id={id}","Queryable":["id"],"Action":"GET"},{"Name":"GetByModelName","Url":"api/driversvoice/get?modelName={modelName}","Queryable":["modelName"],"Action":"GET"},{"Name":"GetEquipmentByBlockId","Url":"api/equipmentdata/get?id={id}","Queryable":["id"],"Action":"GET"},{"Name":"GetDealer","Url":"api/DealerData?dealerId={dealerId}&shopId={shopId}","Queryable":["dealerId","shopId"],"Action":"GET"},{"Name":"SearchDealers","Url":"api/DealerData?searchTerm={searchTerm}&page={page}","Queryable":["searchTerm","page"],"Action":"POST"},{"Name":"GetDealersByCoordinates","Url":"api/DealerData?latitude={latitude}&longitude={longitude}&page={page}","Queryable":["latitude","longitude","page"],"Action":"GET"},{"Name":"GetDealersByPrefecture","Url":"api/DealerData?prefecture={prefecture}&page={page}&dealer={dealer}&groupDealers={groupDealers}","Queryable":["prefecture","page","dealer","groupDealers"],"Action":"GET"},{"Name":"GetDealerCalendar","Url":"api/DealerData?dealerId={dealerId}&shopId={shopId}&page={page}","Queryable":["dealerId","shopId","page"],"Action":"GET"},{"Name":"GetPrefectureList","Url":"api/DealerData?carId={carId}","Queryable":["carId"],"Action":"GET"}];
        // for local testing

        setTimeout(function() {
            // Get language
            this.language = $("body").data("lang");

            // Create index
            if (window.MDPConfig.hasOwnProperty("apiServices")) {
                var apiServices = this.cloneCollection(window.MDPConfig.apiServices);
                apiServices.forEach(function(api) {
                    this.apis[api.Name] = api;

                    // Remove URL parameters
                    this.apis[api.Name].Url = this.apis[api.Name].Url.split("?")[0];

                    // Temporary hack to make all API calls relative to root!!!!
                    this.apis[api.Name].Url = "/" + this.apis[api.Name].Url;
                }.bind(this));
            }
        }.bind(this));
    }

    $__Object$defineProperties(Api.prototype, {
        request: {
            value: function(target, successCallback, errorCallback) {
                var apiName = target.apiName,
                    params = target.params || {},
                    api = this.apis[apiName],
                    messages = [];

                if (!apiName) {
                    errorCallback && errorCallback.call(this, "API name is required");

                    return;
                }

                if (!api) {
                    errorCallback && errorCallback.call(this, "API \"" + apiName + "\" does not exist");

                    return;
                }

                // Apply language
                params.lang = this.language;

                var cacheKey = apiName + JSON.stringify(params);

                if (this.cache[cacheKey] && api.Action === "GET") {
                    successCallback.call(this, this.cache[cacheKey]);
                } else {
                    var ajaxConfig = {
                        type: api.Action,
                        url: api.Url,
                        data: params,
                        success: function(data) {
                            if (api.Action === "GET") {
                                this.cache[cacheKey] = data;
                            }

                            successCallback.call(this, data);
                        }.bind(this),
                        error: errorCallback
                    };

                    if (api.Action === "POST") {
                        ajaxConfig.url += "?lang=" + params.lang;
                        ajaxConfig.contentType = "application/json";
                        ajaxConfig.data = JSON.stringify(ajaxConfig.data);
                    }

                    $.ajax(ajaxConfig);
                }
            },

            enumerable: false,
            writable: true
        },

        cloneCollection: {
            value: function(collection) {
                return JSON.parse(JSON.stringify(collection));
            },

            enumerable: false,
            writable: true
        }
    });

    return Api;
}();

return Api;
});
}).apply(window);/**!!<[service.api]!!**/
/**!![service.cookies]>!!**/
(function(){
registerService("cookies", function(application) {
/**
 * @module Cookies
 */

var $__Object$defineProperties = Object.defineProperties;

var messages = {
    "INVALID_INPUT": "Your input id not valid",
    "COOKIE_GET": "The cookie {name} has the value: {value}",
    "COOKIE_SET": "The cookie {name} was set with value {value}, expiry {}, domain {domain}",
    "COOKIE_REMOVED": "The cookie {name} was removed"
};

var Cookies = function() {
    "use strict";
    function Cookies() {}

    $__Object$defineProperties(Cookies.prototype, {
        getCookie: {
            value: function(name) {
                try {
                    if (typeof name !== "string") {
                        throw new Error(messages.INVALID_INPUT);
                    }

                    // Get cookies
                    var cookies = document.cookie.split(";");

                    for (var i = 0, length = cookies.length; i < length; i++) {
                        var cookie = cookies[i];

                        if (cookie.indexOf(name + "=") > -1) {
                            // Cookie found
                            // TODO use trim
                            var cookieValue = cookie.split("=")[1];

                            console.log(messages.COOKIE_GET
                                .replace("{name}", name)
                                .replace("{value}", cookieValue));

                            return cookieValue;
                        }
                    }

                    return "";
                } catch (exception) {
                    console.log(exception);
                }
                return null;
            },

            enumerable: false,
            writable: true
        },

        setCookie: {
            value: function(name, value, expiry, domain) {
                try {
                    // Input validation
                    if (typeof name !== "string" ||
                        typeof value !== "string" ||
                        expiry && typeof expiry !== "number" ||
                        domain && typeof domain !== "string") {
                        throw new Error(messages.INVALID_INPUT);
                    }

                    var expires = "";

                    if (expiry) {
                        var expiryDate = new Date();
                        expiryDate.setTime(expiryDate.getTime() + expiry);

                        expires = "; expires=" + expiryDate.toUTCString();
                    } else {
                        // Prevents logging 'undefined' for expiry
                        expiry = -1;
                    }

                    if (!domain) {
                        domain = "/";
                    }

                    // Set cookie
                    document.cookie = name + "=" + value + expires + "; path=" + domain;

                    console.log(messages.COOKIE_SET
                        .replace("{name}", name)
                        .replace("{value}", value)
                        .replace("{expiry}", expiry.toString())
                        .replace("{domain}", domain));
                } catch (exception) {
                    console.log(exception);
                }
            },

            enumerable: false,
            writable: true
        },

        removeCookie: {
            value: function(name) {
                try {
                    if (typeof name !== "string") {
                        throw new Error(messages.INVALID_INPUT);
                    }

                    // Remove cookie by setting it with a negative expiry
                    this.setCookie(name, "", -1);

                    console.log(messages.COOKIE_REMOVED.replace("{name}", name));
                } catch (exception) {
                    console.log(exception);
                }
            },

            enumerable: false,
            writable: true
        },

        isCookieSet: {
            value: function(name) {
                try {
                    if (typeof name !== "string") {
                        throw new Error(messages.INVALID_INPUT);
                    }

                    // Find cookie
                    var isCookieSet = false;

                    // We cannot check for "name=" as IE8 does not add the = sign
                    var cookies = "; " + document.cookie;

                    if (cookies.indexOf("; " + name) > -1) {
                        isCookieSet = true;
                    }

                    return isCookieSet;
                } catch (exception) {
                    console.log(exception);
                }
                return null;
            },

            enumerable: false,
            writable: true
        }
    });

    return Cookies;
}();

return new Cookies();
});
}).apply(window);/**!!<[service.cookies]!!**/
/**!![service.geolocation]>!!**/
(function(){
registerService("geolocation", function(application) {
/**
 * @module Geolocation
 */

var $__Object$defineProperties = Object.defineProperties;

var messages = {
	"LOCATION_INVALID": "Unable to determine your location.",
	"LOCATION_GET": "",
	"LOCATION_SET": "",
	"LOCATION_REMOVED": ""
};

var Geolocation = function() {
    "use strict";
    function Geolocation() {}

    $__Object$defineProperties(Geolocation.prototype, {
        getPosition: {
            value: function() {
                var deferred = $.Deferred();

                navigator.geolocation.getCurrentPosition(
                    deferred.resolve,
                    deferred.reject,
                    {
                        enableHighAccuracy: true,
                        timeout: 31000, // high value needed for Samsung S4
                        maximumAge: 90000
                    });

                return deferred.promise();
            },

            enumerable: false,
            writable: true
        }
    });

    return Geolocation;
}();

return new Geolocation();
});
}).apply(window);/**!!<[service.geolocation]!!**/
/**!![service.maps]>!!**/
(function(){
registerService("maps", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var GoogleMap = function() {
    "use strict";
    function GoogleMap() {}

    $__Object$defineProperties(GoogleMap.prototype, {
        loadApi: {
            value: function(pagetools, callback) {
                this.pageWindow = pagetools.window._element[0];

                var pageDocument = this.pageWindow.document,
                    script = pageDocument.createElement("script");


                this.apiLoaded = function (){
                    console.log("apiLoaded");

                    if(typeof(callback) == "function")
                            callback();
                }

                this.pageWindow.initializedMap = function() {
                    console.log("Maps initialize");
                    this.apiLoaded();
                }.bind(this);

                script.type = "text/javascript";

                //Api restricted to *.mazda.co.jp, jp.test.syzygy.co.uk, jp.dev.syzygy.co.uk and localhost
                if(this.checkIfIpAddress()) // if running from ip address dont use mazda business api
                    script.src = "https://maps.googleapis.com/maps/api/js?v=3.20&key=AIzaSyAc5S0TvkSeu9di9gUy20pDqsbSooA7buA";
                else
                    script.src = "https://maps.googleapis.com/maps/api/js?v=3.20&client=gme-mazdamotorcorporation1";

                script.src += "&signed_in=true&callback=initializedMap&language=ja&libraries=places&signed_in=false";


                pageDocument.body.appendChild(script);
            },

            enumerable: false,
            writable: true
        },

        checkIfIpAddress: {
            value: function() {
                var octet = "(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])";
                var ip    = "(?:" + octet + "\\.){3}" + octet;
                var ipRE  = new RegExp( "^" + ip + "$" );

                return ipRE.test( this.pageWindow.location.hostname );
            },

            enumerable: false,
            writable: true
        },

        getLonLat: {
            value: function(val, callback, _this) {
                var geocoder = new this.pageWindow.google.maps.Geocoder(),
                    that = this;
                this.coordinates = [];



                geocoder.geocode( { "address": val, "region": "jp", componentRestrictions: {"country": "jp"}}, function(results, status) {
                    if (status == that.pageWindow.google.maps.GeocoderStatus.OK) {
                        that.coordinates.push(results[0].geometry.location.lng());
                        that.coordinates.push(results[0].geometry.location.lat());

                        if (callback)
                            callback.apply(_this, [that.coordinates]);
                    } else {
                        if (callback)
                           callback.apply(_this, [{"error": "true"}]);
                    }
                });
            },

            enumerable: false,
            writable: true
        },

        keywordSearch: {
            value: function(params, callback, _this, $element) {
                var that = this;

                var service = new google.maps.places.AutocompleteService();

                var geocoder = new this.pageWindow.google.maps.Geocoder();

                geocoder.geocode( { "address": params.val, "region": "jp", componentRestrictions: {"country": "jp"}}, function(results, status) {
                    if(results.length > 0 && !results[0].partial_match){
                        if(callback) {
                            callback.apply(_this, [results, $element, true]);
                        }
                    }else{
                        var displaySuggestions = function(predictions, status) {
                            if(status == "ZERO_RESULTS"){
                                if (callback) {
                                    callback.apply(_this, [[{"error": "true"}], $element, false]);
                                }
                                return;
                            }
                            if (status != google.maps.places.PlacesServiceStatus.OK) {
                                alert(status);
                                return;
                            }

                            console.log(predictions);
                            if (callback) {
                                callback.apply(_this, [predictions, $element, false]);
                            }
                        }


                        service.getPlacePredictions({
                            input: params.val,
                            types: ["(regions)"],
                            componentRestrictions: {"country": "jp"}},
                            displaySuggestions);
                    }
                });
            },

            enumerable: false,
            writable: true
        },

        startMap: {
            value: function(config) {
                var _this = this;
                this.config = config || {};

                //ie8 fix
                $("<img/>")[0].src = this.config.pinIcon;
                //ie8 fix
                $("<img/>")[0].src = this.config.pinIconSelected;



                var mapStyles =[
                    { "featureType": "poi.business", "stylers": [ { "visibility": "on" } ] }
                ];

                var set = google.maps.InfoWindow.prototype.set;
                //disable clicks on pois https://syzygy.teamworkpm.net/tasks/4533382?c=1683270
                google.maps.InfoWindow.prototype.set = function (key, val) {
                    if (key === "map" && ! this.get("noSuppress")) {
                        return;
                    }
                    set.apply(this, arguments);
                }


                this.markers = [];
                var mapOptions = {
                  center: {lat: config.location.latitude, lng: config.location.longitude},
                  zoom: config.zoom,
                  styles: mapStyles
                };


                this.map = new google.maps.Map(this.config.scope,
                mapOptions);

                var pamorama = this.map.getStreetView();

                google.maps.event.addListener(pamorama, "visible_changed", function() {
                    if (pamorama.getVisible()) {
                        if(_this.config.onStreetView)
                            _this.config.onStreetView.apply(this, [true]);
                    } else {
                        if(_this.config.onStreetView)
                            _this.config.onStreetView.apply(this, [false]);
                    }
                });

                this.overlay = new google.maps.OverlayView();
                this.overlay.draw = function() {};
                this.overlay.setMap(this.map);

                google.maps.event.addListener(this.map, "dragend", function(e) {
                    var centre = _this.map.getCenter();
                    if(_this.config.onMapMove)
                        _this.config.onMapMove.apply(this, [centre.lng(), centre.lat()]);
                });

                google.maps.event.addListener(this.map, "zoom_changed", function(e) {
                    if(_this.config.onMapZoom)
                        _this.config.onMapZoom.apply(this, [_this.map.getZoom()]);

                    _this.selectPin(-1);
                });

                google.maps.event.addListener(this.map, "click", function(e) {
                    if(_this.config.onMapClick)
                        _this.config.onMapClick.apply(this, [e]);

                    _this.selectPin(-1);
                });
            },

            enumerable: false,
            writable: true
        },

        getCenter: {
            value: function() {
                return this.map ? this.map.getCenter() : null ;
            },

            enumerable: false,
            writable: true
        },

        buildPins: {
            value: function(dealerCollection) {
                if(this.map){
                    this.clearPins();

                    for(var i = 0; i < dealerCollection.Locations.length; i++) {
                        this.location = dealerCollection.Locations[i];
                        this.shopId = dealerCollection.Locations[i].ShopId;
                        if(this.config.showPins) {
                            this.createPin({lat: this.location.Latitude, lng: this.location.Longitude}, this.shopId, i);
                        }
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        clearPins: {
            value: function() {
                for (var i = 0; i < this.markers.length; i++) {
                    this.markers[i].setMap(null);
                }
                this.markers = [];
            },

            enumerable: false,
            writable: true
        },

        createPin: {
            value: function(location, locationId, index) {
                var _this = this,
                  pinIcon = this.config.firstPin && index == 0 ? this.config.pinIconSelected: this.config.pinIcon;


                var marker = new google.maps.Marker({
                    position: location,
                    mazdaData: index,
                    map: this.map,
                    clickable: true,
                    icon: this.buildIcon(pinIcon, index)
                  });

                this.markers.push(marker);

                google.maps.event.addListener(marker, "click", function(e,a,c,v) {
                    _this.pinClick(this, e);
                });
            },

            enumerable: false,
            writable: true
        },

        selectPin: {
            value: function(selectedId) {
                for (var i = this.config.firstPin && selectedId <= 0 ? 1 : 0 ; i < this.markers.length; i++) {
                    this.markers[i].setIcon(this.buildIcon(this.config.pinIcon, i));
                }

                if(selectedId >=0)
                {
                    this.markers[selectedId].setIcon(this.buildIcon(this.config.pinIconSelected, selectedId));
                }
                else {
                    if(this.config.firstPin &&  this.markers[0])
                      this.markers[0].setIcon(this.buildIcon(this.config.pinIconSelected, 0));


                    this.config.onPinClick.apply(this, [-1]);
                }
            },

            enumerable: false,
            writable: true
        },

        buildIcon: {
            value: function(icon, index) {
                //show blank pin
                if(index >= this.config.numberOfPins || this.config.hideNumbers)
                  index = this.config.numberOfPins;
                var image = {
                   url: icon,
                   size: new google.maps.Size(40, 40),
                   origin: new google.maps.Point(5, 5 + 50 * index),
                   anchor: new google.maps.Point(17, 34)
                 };

                return image;
            },

            enumerable: false,
            writable: true
        },

        pinClick: {
            value: function(_this, e) {
                var point = this.overlay.getProjection().fromLatLngToContainerPixel(e.latLng);

                this.selectPin(_this.mazdaData);
                this.config.onPinClick.apply(this, [_this.mazdaData, point.x, point.y]);
            },

            enumerable: false,
            writable: true
        },

        getBounds: {
            value: function(dealers) {
                var bounds = new google.maps.LatLngBounds();
                for(var i = 0; i < dealers.length; i ++) {
                    var obj = new google.maps.LatLng({lat: dealers[i].Dealer.Address.Latitude, lng: dealers[i].Dealer.Address.Longitude});
                    bounds.extend(obj);
                }
                this.map.fitBounds(bounds);
            },

            enumerable: false,
            writable: true
        }
    });

    return GoogleMap;
}();

return GoogleMap;
});
}).apply(window);/**!!<[service.maps]!!**/
/**!![service.pagetools]>!!**/
(function(){
registerService("pagetools", function(application) {
var ClassList = {
      body: {
        disableoverflow: "disable-overflow"
      },
      header: {
        spillageActive: "primary-spillage-active"
      },
      content: {}
    },
    toolsConfig = {
        media: {
            tabletSmall: 768
        }
    };

/**
 * @constructor
 * @description Pagetools is a Service which mediates interaction between modules and root-level containers.
 */
function PageTools() {
  $(function() {
    this.window = new PageWindow($(window));
    this.body = new ControlSection($("body"), ClassList.body);
    this.header = new ControlSection($(".main-header"), ClassList.header);
    this.content = new MainContentControlSection($(".main-content"), ClassList.content);
    this.logger = new Logr();
    this.layout = new Layout();
  }.bind(this));
}

/**
 * @constructor
 * @param {(HTMLElement|jQuery)=} elementOr$ A HTMLElement or jQuery collection
 * @description The base representation of a top-level content container.
 * Allows for subscribing to a section's events through either an Rx.Observable
 * or via a callback.
 */
function PageSection(elementOr$) {
  this._element = $(elementOr$).first();

  if (!this._element || !this._element.length) {
    console.log("Element not found");
  }
}

/**
 * @public
 * @param {string} domEvent A
 * @param {function=} handler
 * @return {Rx.Observable}
 */
PageSection.prototype.on = function(domEvent, handler) {
  var eventStream = Rx.Observable.fromEvent(this._element, domEvent);

  if (!!handler && typeof handler === "function") {
    eventStream.subscribe(handler);
  }

  return eventStream;
};

/**
 * @constructor
 * @param {(HTMLElement|jQuery)=} elementOr$
 * @extends {PageSection}
 */
function PageWindow(elementOr$) {
  PageSection.apply(this, arguments);
}

PageWindow.prototype = Object.create(PageSection.prototype);

PageWindow.prototype.matchMedia = function(query) {
  var matches = null;

  matches = this._element[0].matchMedia(query);

  return matches;
}

/**
 * @public
 * @description Returns window.location information.
 * @param {boolean} set to true to receive current URL only.
 * @returns {string} or {object}
 *
 */
PageWindow.prototype.location = function(url) {
  return (!!url ? this._element[0].location = url : this._element[0].location);
}

PageWindow.prototype.isCanvasFallbackAvailable = function() {
  return (typeof this._element[0].G_vmlCanvasManager !== "undefined");
}

PageWindow.prototype.G_vmlCanvasManager = function() {
  if(!this.isCanvasFallbackAvailable()) return false;

  return this._element[0].G_vmlCanvasManager;
}

PageWindow.prototype.pageResize = function(callback) {
  var _window = this._element[0];
  $(_window).resize(function() {
    if (callback) {
      return callback();
    }
  });
}

/**
 * @public
 * @description Checks if current viewport resolution is mobile,
 * lower than the configured or passed in breakpoint.
 * @param {number} Media resolution - Overrides default configuration
 * @returns {boolean}
 *
 */
PageWindow.prototype.isMobile = function(viewportResolution) {
  var _window = this._element[0],
      resolution = viewportResolution || toolsConfig.media.tabletSmall,
      width = _window.innerWidth || _window.document.documentElement.clientWidth || _window.document.body.clientWidth;
  return width < resolution;
}

/**
 * @public
 * @description Gets the current browser touch event types (touch, pointer...).
 * The returned event will be different from touch to pointer, so the implementation needs to account for that.
 * @returns {object}
 *
 */
PageWindow.prototype.touchEvents = function() {
  var _window = this._element[0],
      _touchStart = "touchstart",
      _touchMove = "touchmove",
      _touchEnd = "touchend",
      _touchCancel = "touchcancel";

  // Config for Touch/Pointer events
  if (_window.navigator.pointerEnabled) {
    _touchStart = "pointerdown";
    _touchMove = "pointermove";
    _touchEnd = "pointerup";
    _touchCancel = "pointercancel";
  } else if (_window.navigator.msPointerEnabled) {
    _touchStart = "MSPointerDown";
    _touchMove = "MSPointerMove";
    _touchEnd = "MSPointerUp";
    _touchCancel = "MSPointerCancel";
  }
  return {
      touchStart: _touchStart,
      touchMove: _touchMove,
      touchEnd: _touchEnd,
      touchCancel: _touchCancel
  }
}

/**
 * @public
 * @description Used to apply an offset to the page body.
 * @returns {object}
 */
PageWindow.prototype.pageOffset = function() {
  // Used for the mobile fixed menu and to scrolling on iPhone
  var $body = $("body"),
      $header = $body.children("header"),
      _get = function() {
        var headerHeight = $header.length > 0 ? $header.height() : 0;
        return this._element.scrollTop();
      }.bind(this),
      _set = function(pageOffsetValue) {
        if ($body.css("position") === "fixed") {
          $body.css("top", (-1 * pageOffsetValue) + "px");
        }
      },
      _reset = function() {
        var bodyOffset = parseInt($body.offset().top) === 0 ? _get() : $body.offset().top;
        bodyOffset = bodyOffset < 0 ? bodyOffset * -1 : bodyOffset;
        $body.css("top", "");
        this._element.scrollTop(bodyOffset);
      }.bind(this);
  return {
      get: _get,
      set: _set,
      reset: _reset
  }
}

/**
 * @public
 * @description Toggles ability to scoll the page. Applied only to the body.
 */
PageWindow.prototype.togglePageScroll = function() {
  var $body = $("body"),
      pageOffset = this.pageOffset(),
      pageOffsetValue = pageOffset.get(),
      bodyIsFixed = function() {
        return $body.css("position") === "fixed";
      };

  if ($body.hasClass("disable-overflow")) {
    // Store before removing the class
    bodyIsFixed = bodyIsFixed();
    $body.removeClass("disable-overflow");
    if (bodyIsFixed) {
      pageOffset.reset();
    }
  } else {
    $body.addClass("disable-overflow");
    if (bodyIsFixed()) {
      pageOffset.set(pageOffsetValue);
    }
  }
}

/**
 * @public
 * @description Scrolls to a specifc location on the page. Takes into account the floating mobile navigation
 */
PageWindow.prototype.scrollOffsetTop = function(offset) {
  var _window = $(this._element[0])
    , _mobileHeader = $(".main-header");

  // If is mobile offset the static header height
  if(_window.width() <= 768) {
    offset = offset - _mobileHeader.height();
  }

  _window.scrollTop(offset);
}


/**
 * @constructor
 * @param {(HTMLElement|jQuery)=} elementOr$
 * @param {object} classList
 * @extends {PageSection}
 */
function ControlSection(elementOr$, classList) {
  var data, attributeClassList;
  PageSection.apply(this, arguments);

  data = this._element.data();

  if (!data) {
    return;
  }

  attributeClassList = Object.keys(data)
    .filter(function(s) {
    return s.indexOf("pagetoolsClass") === 0;
  })
    .reduce(function(a, b) {
    var key = b.replace("pagetoolsClass", "");
    key = key[0].toLowerCase() + key.slice(1);
    a[key] = data[b];
    return a;
  }, {});

  this._classList = $.extend({},
                             attributeClassList,
                             classList || {});
}

ControlSection.prototype = Object.create(PageSection.prototype);

/**
 * @public
 * @description Returns width of the Header.
 * @param {boolean} include margin
 * @returns {integer}
 *
 */
ControlSection.prototype.getHeaderWidth = function(includeMargin) {
  return this._element.find("> .container").outerWidth(includeMargin);
}

/**
 * @public
 * @description Toggles header spillage class.
 *
 */
ControlSection.prototype.toggleHeaderSpillageClass = function(state) {
  this._element.toggleClass(this._classList.spillageActive, state);
}

/**
 * @public
 * @description Returns Purchase Tool Width.
 * @param {boolean} include margin
 * @returns {integer}
 *
 */
ControlSection.prototype.getPurchaseToolWidth = function(includeMargin) {
  return this._element.find(".module-purchase-tool-menu > ul").outerWidth(includeMargin);
}

/**
 * @return {Array}
 *
 * Get classList for this {ControlSection}
 */
ControlSection.prototype.classList = function() {
  return this._classList;
};

/**
 * @public
 * @param {string} classNameOrId
 * @return {boolean}
 *
 * Check for the existence of a class on this {ControlSection}
 */
ControlSection.prototype.hasClass = ClassManipulator("hasClass");

/**
 * @public
 * @param {string} classId
 *
 * Adds a class to the element controlled by this {ControlSection}
 */
ControlSection.prototype.addClass = ClassManipulator("addClass");

/**
 * @public
 * @param {string} classId
 *
 * Adds a class to the element controlled by this {ControlSection}
 */
ControlSection.prototype.removeClass = ClassManipulator("removeClass");

/**
 * @public
 * @param {string} classId
 *
 * Adds a class to the element controlled by this {ControlSection}
 */
ControlSection.prototype.toggleClass = ClassManipulator("toggleClass");

/**
 * @constructor
 * @description The base of a logging system that is consistent accross all browsers
 */
//TODO: Silencing system
function Logr(){}

/**
 * @public
 * @param {array}
 * @description Centralised Logging system
 */
Logr.prototype.log = function() {
  var i = -1,
    l = arguments.length,
    args = [],
    fn = "console.log(args)";

  while(++i<l){
    args.push("args["+i+"]");
  }

  fn = new Function("args",fn.replace(/args/,args.join(",")));

  fn(arguments);
};

/**
 * @private
 * @param {string} fn
 * @return {void}
 */
function ClassManipulator(fn) {
  return function(classNameOrId) {
    var className = classNameOrId in this._classList ?
      this._classList[classNameOrId] :
      classNameOrId;

    console.log("ClassManipulator", fn, classNameOrId);
    return !!(this._element[fn](className));
  }
}

/**
 * @constructor
 * @param {(HTMLElement|jQuery)=} elementOr$
 * @param {object} classList
 * @extends {ControlSection}
 */
function MainContentControlSection(elementOr$, classList) {
  ControlSection.apply(this, arguments);
}

MainContentControlSection.prototype = Object.create(ControlSection.prototype);

/**
 * @type Number
 */
MainContentControlSection.prototype.height = function(value) {
  return value ? this._element.height() : this._element.height(value);
}
// Viewport height

/**
 * @constructor
 * @description Layout information
 */
function Layout(){}

/**
 * @public
 * @param {jQuery} module
 * @description Get color and name of the Layout
 */
Layout.prototype.getLayout = function(module) {
  if (!module) return;
  var layout = module.closest(".layout"),
      layoutBg = layout.css("background-color") || "rgb(32, 32, 32)";
  return {
    rgbColor: layoutBg,
    hexColor: (layoutBg.charAt(0) === "#") ? layoutBg.slice(1) : rgb2hex(layoutBg),
    layoutType: layout.hasClass("light") ? "light" : "dark"
  };
};

/**
 * @private
 * @param {string} rgb
 * @description Turn rgb to hex (based on http://wowmotty.blogspot.co.uk/2009/06/convert-jquery-rgb-output-to-hex-color.html)
 */
function rgb2hex(rgb) {
  rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
  return ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) +
    ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) +
    ("0" + parseInt(rgb[3],10).toString(16)).slice(-2);
}

/**
 * @module PageTools
 * @description Pagetools is an MDPFramework Service for manipulating a page's top-level
 * content containers: <code>window</code>, <code>body</code>, .<code>main-header</code>, <code>.main-content</code>.
 */
return PageTools;
});
}).apply(window);/**!!<[service.pagetools]!!**/
/**!![service.session]>!!**/
(function(){
registerService("session", function(application) {
var $__Object$defineProperties = Object.defineProperties;

var Session = function() {
  "use strict";

  function Session() {
    this.sessionApi = "/api/session/user";
    this.visitApi = "/api/session/visit";

    setTimeout(function() {
      //window.MDPConfig.visitInfo = {"SessionId":"815d5a92-4c00-4053-a370-40f9373079b0","Url":null,"FormType":null,"Tags":null};
      this.visitInfo = window.MDPConfig.visitInfo;

      // visitInfo will always be included by the server,
      //  however, this may return a null SessionId if that site does not have session enabled
      if (window.MDPConfig.visitInfo && window.MDPConfig.visitInfo.SessionId) {
        window.MDPConfig.visitInfo.Url = this.visitInfo.Url = window.location.pathname + window.location.search;

        // Log visit info
        $.ajax({
          type: "POST",
          url: this.visitApi,
          data: window.MDPConfig.visitInfo,
          error: function(e) {
            console.log(e);
          }
        });

        // Showroom page logic
        var carId = $("meta[name=\"pageinfo.carid\"]").attr("content");

        if (carId) {
          // Find out if there's any car id set in session
          this.get(function(data) {
            if (this.isValidJson(data) && data.Data && !data.Data.carid) {
              // If no car id set
              // Set session with car id from showroom page
              this.set("carid", carId);
            }
          }.bind(this));
        }
      }
    }.bind(this));
  }

  $__Object$defineProperties(Session.prototype, {
    get: {
      value: function(callback) {
        // Does a SessionId exist? if not then use localStorage
        if (window.MDPConfig.visitInfo && window.MDPConfig.visitInfo.SessionId) {
          // Temporary cache busting workaround
          // This must be refactored at a later date
          var cacheBuster = new Date().getTime(),
          sessionId = window.MDPConfig.visitInfo.SessionId;

          $.get(this.sessionApi + "?id=" + sessionId + "&t=" + cacheBuster, function(data) {
            callback.apply(this, [data]);
          }.bind(this));
        } else {
          var data = {
            Data: {}
          };

          for (var i = 0; i < localStorage.length; i++) {
            var key = localStorage.key(i),
            keyValue = localStorage.getItem(key);

            // we spoof this "Data" key so we don't have to change our module code.
            data.Data[key.toLowerCase()] = keyValue;
          }

          callback.apply(this, [data]);
        }
      },

      enumerable: false,
      writable: true
    },

    set: {
      value: function(key, value, successCallback, errorCallback) {
        if (typeof value !== "string" && typeof value !== "number") {
          console.log("Value must be a string or number.");

          if (errorCallback) {
            errorCallback.apply(this);
          }
        }

        // Does a SessionId exist? if not then use localStorage
        if (window.MDPConfig.visitInfo && window.MDPConfig.visitInfo.SessionId) {
          var message = {
            SessionId: window.MDPConfig.visitInfo.SessionId,
            Values: [{
              Key: key,
              Value: value
            }]
          };

          $.ajax({
            type: "POST",
            url: this.sessionApi,
            data: message,
            success: successCallback,
            error: errorCallback
          });
        } else {
          try {
            // we must set lowercase for the key as the backend does the same.
            localStorage.setItem(key.toLowerCase(), value);
            successCallback.apply(this);
          } catch (e) {
            errorCallback.apply(this);
          }
        }
      },

      enumerable: false,
      writable: true
    },

    setValues: {
      value: function(values, successCallback, errorCallback) {
        // Does a SessionId exist? if not then use localStorage
        if (window.MDPConfig.visitInfo && window.MDPConfig.visitInfo.SessionId) {
          var message = {
            SessionId: window.MDPConfig.visitInfo.SessionId,
            Values: values
          };

          $.ajax({
            type: "POST",
            url: this.sessionApi,
            data: message,
            success: successCallback,
            error: errorCallback
          });
        } else {
          try {
            if (Array.isArray(values)) {
              for (var i = 0; i < values.length; i++) {
                var key = values[i]["key"],
                value = values[i]["value"];

                localStorage.setItem(key.toLowerCase(), value);
              }
              successCallback.apply(this);
            }
          } catch (e) {
            console.log(e);
            errorCallback.apply(this);
          }
        }
      },

      enumerable: false,
      writable: true
    },

    updateAnchorSessionIdNull: {
      value: function() {
        var sessionId = window.MDPConfig.visitInfo.SessionId;

        $("a[href]").attr("href",function(i,val){
          return val.replace("sessionid=null", "sessionid=" + sessionId);
        }.bind(this));
      },

      enumerable: false,
      writable: true
    },

    isValidJson: {
      value: function(value) {
        try {
          JSON.parse(value);

          return true;
        } catch (e) {
          return false;
        }
      },

      enumerable: false,
      writable: true
    }
  });

  return Session;
}();

return Session;
});
}).apply(window);/**!!<[service.session]!!**/
}).apply(window);/**!!<[core]!!**/
/**!![ModulePromos]>!!**/(function(){"use strict";Modules.registerModule("ModulePromos","",function(){})}).apply(window);/**!!<[ModulePromos]!!**/
/**!![ModuleCarousel]>!!**/
(function(){
registerModule("ModuleCarousel", "core", function() {
"use strict";
});
}).apply(window);/**!!<[ModuleCarousel]!!**/
/**!![ModuleCopy]>!!**/(function(){"use strict";Modules.registerModule("ModuleCopy","",function(){})}).apply(window);/**!!<[ModuleCopy]!!**/
/**!![ModuleHeaderSearch]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_auto-suggest"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "	    <li><a title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.word : depth0), depth0))
    + "\" href=\"#\">"
    + escapeExpression(lambda((depth0 != null ? depth0.word : depth0), depth0))
    + "</a></li>   \n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"autosuggest\">\n	<ul>\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "	</ul>\n</div>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('ModuleHeaderSearch.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerModule("ModuleHeaderSearch", "core", function() {
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */
});
}).apply(window);/**!!<[ModuleHeaderSearch]!!**/
/**!![ModuleVideo]>!!**/
(function(){
registerModule("ModuleVideo", "core", function() {
"use strict";
});
}).apply(window);/**!!<[ModuleVideo]!!**/
/**!![ModuleGallery]>!!**/
(function(){
registerModule("ModuleGallery", "core", function() {
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */
});
}).apply(window);/**!!<[ModuleGallery]!!**/
/**!![ModuleSocialMedia_com]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_blog"] = Handlebars.template({"1":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "<div class=\"res-1024-cols-"
    + escapeExpression(lambda(((stack1 = (depths[1] != null ? depths[1].options : depths[1])) != null ? stack1.size : stack1), depth0))
    + " item blog\">\n    <div class=\"ratio-wrapper\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.image : depth0), {"name":"if","hash":{},"fn":this.program(2, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "        <div class=\"content\">\n            <h2 class=\"category blog\"><a target=\"_blank\" href=\""
    + escapeExpression(lambda((depths[1] != null ? depths[1].channelUrl : depths[1]), depth0))
    + "\">"
    + escapeExpression(lambda((depths[1] != null ? depths[1].title : depths[1]), depth0))
    + "</a></h2>\n            <div class=\"details\">\n                <p><a target=\"_blank\" href=\""
    + escapeExpression(lambda((depth0 != null ? depth0.link : depth0), depth0))
    + "\">"
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "</a></p>\n            </div>\n            <div class=\"description\">\n                <p>"
    + escapeExpression(lambda((depth0 != null ? new DOMParser().parseFromString(depth0.description, 'text/html').body.innerText : depth0), depth0))
    + "</p>\n            </div>\n            <a class=\"read-more-link\" target=\"_blank\" href=\""
    + escapeExpression(lambda((depth0 != null ? depth0.link : depth0), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = (depths[1] != null ? depths[1].resources : depths[1])) != null ? stack1.readMore : stack1), depth0))
    + "</a>\n        </div>\n    </div>\n</div>\n";
},"2":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "            <a class=\"image\" target=\"_blank\" href=\""
    + escapeExpression(lambda((depth0 != null ? depth0.link : depth0), depth0))
    + "\" style=\"background-image:url("
    + escapeExpression(lambda((depth0 != null ? depth0.image : depth0), depth0))
    + ");\">\n                <img title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" src=\""
    + escapeExpression(lambda((depth0 != null ? depth0.image : depth0), depth0))
    + "\">\n            </a>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing;
  stack1 = ((helpers.limited_each || (depth0 && depth0.limited_each) || helperMissing).call(depth0, (depth0 != null ? depth0.feed : depth0), {"name":"limited_each","hash":{
    'limit': (((stack1 = (depth0 != null ? depth0.options : depth0)) != null ? stack1.totalItems : stack1))
  },"fn":this.program(1, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { return stack1; }
  else { return ''; }
  },"useData":true,"useDepths":true});
this["templates"]["_facebook"] = Handlebars.template({"1":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "<div class=\"res-1024-cols-"
    + escapeExpression(lambda(((stack1 = (depths[1] != null ? depths[1].options : depths[1])) != null ? stack1.size : stack1), depth0))
    + " facebook item\">\n    <div class=\"ratio-wrapper\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.picture : depth0), {"name":"if","hash":{},"fn":this.program(2, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "        <div class=\"content\">\n            <h2 class=\"category facebook\"><a target=\"_blank\" href=\""
    + escapeExpression(lambda((depths[1] != null ? depths[1].channelUrl : depths[1]), depth0))
    + "/"
    + escapeExpression(lambda((depth0 != null ? depth0.page_id : depth0), depth0))
    + "\">"
    + escapeExpression(lambda((depths[1] != null ? depths[1].title : depths[1]), depth0))
    + "</a></h2>\n            <div class=\"details\">\n                <p><a target=\"_blank\" href=\""
    + escapeExpression(lambda((depths[1] != null ? depths[1].channelUrl : depths[1]), depth0))
    + "/"
    + escapeExpression(lambda((depth0 != null ? depth0.page_id : depth0), depth0))
    + "\">"
    + escapeExpression(lambda((depth0 != null ? depth0.page_name : depth0), depth0))
    + "</a><span class=\"date\">"
    + escapeExpression(lambda((depth0 != null ? depth0.createdDate : depth0), depth0))
    + "</span></p>\n            </div>\n            <div class=\"description\">\n                <p>"
    + escapeExpression(lambda((depth0 != null ? depth0.message : depth0), depth0))
    + "</p>\n            </div>\n            <a class=\"read-more-link\" target=\"_blank\" href=\""
    + escapeExpression(lambda((depths[1] != null ? depths[1].channelUrl : depths[1]), depth0))
    + "/"
    + escapeExpression(lambda((depth0 != null ? depth0.page_id : depth0), depth0))
    + "/posts/"
    + escapeExpression(lambda((depth0 != null ? depth0.post_id : depth0), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = (depths[1] != null ? depths[1].resources : depths[1])) != null ? stack1.readMore : stack1), depth0))
    + "</a>\n        </div>\n    </div>\n</div>\n";
},"2":function(depth0,helpers,partials,data,depths) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "            <a class=\"image\" target=\"_blank\" href=\""
    + escapeExpression(lambda((depths[2] != null ? depths[2].channelUrl : depths[2]), depth0))
    + "/"
    + escapeExpression(lambda((depth0 != null ? depth0.page_id : depth0), depth0))
    + "/posts/"
    + escapeExpression(lambda((depth0 != null ? depth0.post_id : depth0), depth0))
    + "\" style=\"background-image:url("
    + escapeExpression(lambda((depth0 != null ? depth0.picture : depth0), depth0))
    + ");\">\n                <img src=\""
    + escapeExpression(lambda((depth0 != null ? depth0.picture : depth0), depth0))
    + "\">\n            </a>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing, buffer = "";
  stack1 = ((helpers.limited_each || (depth0 && depth0.limited_each) || helperMissing).call(depth0, (depth0 != null ? depth0.feed : depth0), {"name":"limited_each","hash":{
    'limit': (((stack1 = (depth0 != null ? depth0.options : depth0)) != null ? stack1.totalItems : stack1))
  },"fn":this.program(1, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"useData":true,"useDepths":true});
this["templates"]["_pinterest"] = Handlebars.template({"1":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<div class=\"res-1024-cols-"
    + escapeExpression(lambda(((stack1 = (depths[1] != null ? depths[1].options : depths[1])) != null ? stack1.size : stack1), depth0))
    + " item pinterest\">\n	<div class=\"ratio-wrapper\">\n        <a href=\""
    + escapeExpression(lambda((depths[1] != null ? depths[1].channelUrl : depths[1]), depth0))
    + "/"
    + escapeExpression(lambda((depth0 != null ? depth0.boardurl : depth0), depth0))
    + "\" target=\"_blank\" class=\"image\">\n	        <img src=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.thumbnail : depth0)) != null ? stack1.url : stack1), depth0))
    + "\">\n	    </a>\n	    <div class=\"content\">\n	        <h2 class=\"category pinterest\"><a target=\"_blank\" title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.boardname : depth0), depth0))
    + " Pinterest\" href=\""
    + escapeExpression(lambda((depths[1] != null ? depths[1].channelUrl : depths[1]), depth0))
    + "/"
    + escapeExpression(lambda((depth0 != null ? depth0.boardurl : depth0), depth0))
    + "\">"
    + escapeExpression(lambda((depths[1] != null ? depths[1].title : depths[1]), depth0))
    + "</a></h2>\n	    </div>\n    </div>\n</div>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing;
  stack1 = ((helpers.limited_each || (depth0 && depth0.limited_each) || helperMissing).call(depth0, (depth0 != null ? depth0.feed : depth0), {"name":"limited_each","hash":{
    'limit': (((stack1 = (depth0 != null ? depth0.options : depth0)) != null ? stack1.totalItems : stack1))
  },"fn":this.program(1, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { return stack1; }
  else { return ''; }
  },"useData":true,"useDepths":true});
this["templates"]["_tabs"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, buffer = "";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.program(4, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"2":function(depth0,helpers,partials,data) {
  return "    		<li class=\"selected\"><a class=\"default\" title=\"Latest social media\" href=\"#\">Latest</a></li>\n";
  },"4":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "    		<li><a class=\"social-icon "
    + escapeExpression(lambda((depth0 != null ? depth0.id : depth0), depth0))
    + "-icon\" title=\"Latest of "
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" href=\"#\">"
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "</a></li>\n";
},"6":function(depth0,helpers,partials,data) {
  var stack1, buffer = "";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(7, data),"inverse":this.program(9, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer;
},"7":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, buffer = "	    	<li class=\"selected\">";
  stack1 = ((helper = (helper = helpers.content || (depth0 != null ? depth0.content : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"content","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</li>\n";
},"9":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "	    	<li data-social-media=\""
    + escapeExpression(lambda((depth0 != null ? depth0.id : depth0), depth0))
    + "\"></li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<ul class=\"helper-tabs level-1\"> \n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "</ul>\n<ul class=\"helper-tabs level-2 clearfix\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</ul>";
},"useData":true});
this["templates"]["_twitter"] = Handlebars.template({"1":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "<div class=\"res-1024-cols-"
    + escapeExpression(lambda(((stack1 = (depths[1] != null ? depths[1].options : depths[1])) != null ? stack1.size : stack1), depth0))
    + " twitter item\">\n    <div class=\"ratio-wrapper\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.Image : depth0), {"name":"if","hash":{},"fn":this.program(2, data, depths),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "        <div class=\"content\">\n            <h2 class=\"category twitter\">\n";
  stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 != null ? depth0.Retweet : depth0)) != null ? stack1.Name : stack1), {"name":"if","hash":{},"fn":this.program(4, data, depths),"inverse":this.program(6, data, depths),"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "            </h2>\n            <div class=\"details\">\n";
  stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 != null ? depth0.Retweet : depth0)) != null ? stack1.Name : stack1), {"name":"if","hash":{},"fn":this.program(8, data, depths),"inverse":this.program(10, data, depths),"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "            </div>\n            <div class=\"description\">\n                <p>";
  stack1 = lambda((depth0 != null ? depth0.Title : depth0), depth0);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</p>\n            </div>\n            <a class=\"read-more-link\" target=\"_blank\" href=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Link : depth0)) != null ? stack1.Url : stack1), depth0))
    + "\">"
    + escapeExpression(lambda(((stack1 = (depths[1] != null ? depths[1].resources : depths[1])) != null ? stack1.readMore : stack1), depth0))
    + "</a>\n        </div>\n    </div>\n</div>\n";
},"2":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "            <div class=\"image\" style=\"background-image:url("
    + escapeExpression(lambda((depth0 != null ? depth0.Image : depth0), depth0))
    + ");\">\n                <img src=\""
    + escapeExpression(lambda((depth0 != null ? depth0.Image : depth0), depth0))
    + "\">\n            </div>\n";
},"4":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                    <a target=\"_blank\" href=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Retweet : depth0)) != null ? stack1.Url : stack1), depth0))
    + "\">"
    + escapeExpression(lambda((depths[2] != null ? depths[2].title : depths[2]), depth0))
    + "</a>\n";
},"6":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                    <a target=\"_blank\" href=\""
    + escapeExpression(lambda((depths[2] != null ? depths[2].channelUrl : depths[2]), depth0))
    + "/"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Author : depth0)) != null ? stack1.Nickname : stack1), depth0))
    + "\">"
    + escapeExpression(lambda((depths[2] != null ? depths[2].title : depths[2]), depth0))
    + "</a>\n";
},"8":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                    <p>"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Retweet : depth0)) != null ? stack1.Name : stack1), depth0))
    + " retweeted "
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Author : depth0)) != null ? stack1.Name : stack1), depth0))
    + " <a target=\"_blank\" href=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Author : depth0)) != null ? stack1.Url : stack1), depth0))
    + "\">@"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Author : depth0)) != null ? stack1.Nickname : stack1), depth0))
    + "</a><span class=\"date\">"
    + escapeExpression(lambda((depth0 != null ? depth0.createdDate : depth0), depth0))
    + "</span></p>\n";
},"10":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                    <p>"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Author : depth0)) != null ? stack1.Name : stack1), depth0))
    + " <a target=\"_blank\" href=\""
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Author : depth0)) != null ? stack1.Url : stack1), depth0))
    + "\">@"
    + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.Author : depth0)) != null ? stack1.Nickname : stack1), depth0))
    + "</a><span class=\"date\">"
    + escapeExpression(lambda((depth0 != null ? depth0.createdDate : depth0), depth0))
    + "</span></p>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing;
  stack1 = ((helpers.limited_each || (depth0 && depth0.limited_each) || helperMissing).call(depth0, (depth0 != null ? depth0.feed : depth0), {"name":"limited_each","hash":{
    'limit': (((stack1 = (depth0 != null ? depth0.options : depth0)) != null ? stack1.totalItems : stack1))
  },"fn":this.program(1, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { return stack1; }
  else { return ''; }
  },"useData":true,"useDepths":true});
this["templates"]["_youtube"] = Handlebars.template({"1":function(depth0,helpers,partials,data,depths) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "<div class=\"res-1024-cols-"
    + escapeExpression(lambda(((stack1 = (depths[1] != null ? depths[1].options : depths[1])) != null ? stack1.size : stack1), depth0))
    + " item youtube\">\n    <div class=\"ratio-wrapper\">\n        <div class=\"image\" style=\"background-image: url("
    + escapeExpression(lambda((depth0 != null ? depth0.thumbnail : depth0), depth0))
    + ");\">\n            <a target=\"_blank\" title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + " youtube video\" href=\""
    + escapeExpression(lambda((depths[1] != null ? depths[1].channelUrl : depths[1]), depth0))
    + "/video/"
    + escapeExpression(lambda((depth0 != null ? depth0.id : depth0), depth0))
    + "\">\n                <img alt=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" src=\""
    + escapeExpression(lambda((depth0 != null ? depth0.thumbnail : depth0), depth0))
    + "\">\n            </a>\n        </div>\n        <div class=\"content\">\n            <h2 class=\"category youtube\"><a target=\"_blank\" title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + " youtube video\" href=\""
    + escapeExpression(lambda((depths[1] != null ? depths[1].channelUrl : depths[1]), depth0))
    + "/video/"
    + escapeExpression(lambda((depth0 != null ? depth0.id : depth0), depth0))
    + "\">"
    + escapeExpression(lambda((depths[1] != null ? depths[1].title : depths[1]), depth0))
    + "</a></h2>\n            <div class=\"details\">\n                <p><a target=\"_blank\" href=\""
    + escapeExpression(lambda((depths[1] != null ? depths[1].channelUrl : depths[1]), depth0))
    + "/channel/"
    + escapeExpression(lambda((depth0 != null ? depth0.channelId : depth0), depth0))
    + "\">"
    + escapeExpression(lambda((depth0 != null ? depth0.channelTitle : depth0), depth0))
    + "</a></p>\n            </div>\n            <div class=\"description\">\n                <p>"
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "</p>\n            </div>\n        </div>\n    </div>\n</div>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data,depths) {
  var stack1, helperMissing=helpers.helperMissing;
  stack1 = ((helpers.limited_each || (depth0 && depth0.limited_each) || helperMissing).call(depth0, (depth0 != null ? depth0.feed : depth0), {"name":"limited_each","hash":{
    'limit': (((stack1 = (depth0 != null ? depth0.options : depth0)) != null ? stack1.totalItems : stack1))
  },"fn":this.program(1, data, depths),"inverse":this.noop,"data":data}));
  if (stack1 != null) { return stack1; }
  else { return ''; }
  },"useData":true,"useDepths":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('ModuleSocialMedia.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerModule("ModuleSocialMedia", "com", function() {
/*
 * @module Gallery
 */

/**
 * @class Gallery
 * @classdesc Renders a tabbed gallery inside an overlay
 */
var $__Object$defineProperties = Object.defineProperties;
var moduleLog = "ModuleSocialMedia: ";

var SocialMedia = function() {
    "use strict";

    function SocialMedia() {
        this.socialMedia = [];
        this.resources = {};
        this.tabsFeeds = {};
        this.config = {
            channelUrl: {
                blog: "https://blog.mazda.com",
                facebook: "https://www.facebook.com",
                twitter: "https://twitter.com",
                youtube: "https://www.youtube.com",
                pinterest: "https://www.pinterest.com"
            },
            layout: {
                small: "4", // 3 column layout
                wide: "8", // 3 column layout, 1 wide
                full: "12",
                itemsPerRow: {
                    base: 3,
                    latest: [2, 3]
                },
                getColumnsSize: function (columnsLayout) {
                    return this[columnsLayout];
                }
            },
            language: {
            // The order of latestTemplateOptions affects the latest tab content order
            // Defaults for different languages
                ja: {
                    latestTemplateOptions: {
                        twitter: {
                            size: "small",
                            totalItems: 1
                        },
                        facebook: {
                            size: "wide",
                            totalItems: 1
                        },
                        youtube: {
                            size: "small",
                            totalItems: 1
                        },
                        pinterest: {
                            size: "small",
                            totalItems: 1
                        },
                        blog: {
                            size: "small",
                            totalItems: 1
                        }
                    }
                },
                en: {
                    latestTemplateOptions: {
                        twitter: {
                            size: "small",
                            totalItems: 1
                        },
                        facebook: {
                            size: "small",
                            totalItems: 1
                        },
                        youtube: {
                            size: "small",
                            totalItems: 1
                        },
                        pinterest: {
                            size: "small",
                            totalItems: 1
                        },
                        blog: {
                            size: "small",
                            totalItems: 1
                        }
                    }
                }
            }
        };
        this.tabs = {
            items: [{
                id: "latest",
                title: "Latest"
            }]
        };
        this.latestTemplateOptions = {};
        this.defaultTemplateOptions = {
            twitter: {
                size: "small",
                totalItems: 27
            },
            facebook: {
                size: "small",
                totalItems: 27
            },
            youtube: {
                size: "small",
                totalItems: 27
            },
            pinterest: {
                size: "small",
                totalItems: 27
            },
            blog: {
                size: "small",
                totalItems: 27
            }
        };
        setTimeout(function() {
            this.pagetools = Services("pagetools");
            this.init();
        }.bind(this));
    }

    $__Object$defineProperties(SocialMedia.prototype, {
        init: {
            value: function() {
                var tabsTemplate = {
                        items: [],
                        content: null
                    };
                this._window = this.pagetools.window._element[0];
                this.$body = this.pagetools.body._element;
                this.getFeed();
                this.setTemplates();
            },

            enumerable: false,
            writable: true
        },

        getFeed: {
            value: function() {
                try {
                    var apiLocation = view.$.attr("data-service"), // Gets social media providers from module
                        windowProtocol = this._window.location.protocol,
                        windowHost = this._window.location.host,
                        apiUrl = windowProtocol + "//" + windowHost + "/" + apiLocation;

                    this.getData(apiUrl)
                        .done(function(data) {
                        this.socialMedia = data.data || [];
                        this.resources = data.resources;
                        if ($.isArray(this.socialMedia) && this.socialMedia.length > 1) {
                            this.setTabsFeeds();
                        } else if (this.socialMedia.length > 0) {
                            this.startSingleFeed();
                        } else {
                            console.log(moduleLog + "There are no social media feeds");
                        }
                    }.bind(this))
                        .fail(function(data) {
                        console.log(moduleLog + "Social Media request failed: " + data);
                    });
                } catch (e) {
                    console.log(moduleLog);
                    throw new Error(e);
                }
            },

            enumerable: false,
            writable: true
        },

        setTemplates: {
            value: function() {
                this.Templates = {
                    _tabs: Services("templateService").templates("ModuleSocialMedia._tabs"),
                    _twitter: Services("templateService").templates("ModuleSocialMedia._twitter"),
                    _facebook: Services("templateService").templates("ModuleSocialMedia._facebook"),
                    _pinterest: Services("templateService").templates("ModuleSocialMedia._pinterest"),
                    _youtube: Services("templateService").templates("ModuleSocialMedia._youtube"),
                    _blog: Services("templateService").templates("ModuleSocialMedia._blog")
                };
            },

            enumerable: false,
            writable: true
        },

        startSingleFeed: {
            value: function() {
                var socialMedia = this.socialMedia,
                    tabHtml,
                    options = {},
                    $element = [],
                    totalItems = socialMedia[0].feed.length,
                    wrapItemsNumber = 1;

                this.singleFeed = {};
                this.singleFeed[socialMedia[0].id] = socialMedia[0];
                this.singleFeed[socialMedia[0].id].channelUrl = this.config.channelUrl[socialMedia[0].id];
                this.singleFeed[socialMedia[0].id].resources = this.resources;
                this.postProcessFeeds(true);

                if (totalItems === 1) {
                    // Full width item if only 1 exists
                    options[socialMedia[0].id] = {"size": this.config.layout.full};
                    view.$.addClass("single-item");
                } else {
                    // 3 columns width
                    options[socialMedia[0].id] = {"size": this.config.layout.small};
                }
                wrapItemsNumber = 12 / parseInt(options[socialMedia[0].id].size);
                tabHtml = this.renderTemplate (this.singleFeed, options);
                tabHtml = wrapItemsNumber > 1 ? this.wrapItems(tabHtml, wrapItemsNumber) : tabHtml;
                view.$.append(tabHtml);
                $element = view.$.find(".item");
                this.checkImagesLoaded($element, [this.itemContentOffset, this.clipText]);
            },

            enumerable: false,
            writable: true
        },

        setTabsFeeds: {
            value: function() {
                var socialMedia = this.socialMedia,
                    tabsSet = false;

                this.latestTemplateOptions = this.siteLanguage("en") ?
                                             this.config.language.en.latestTemplateOptions :
                                             this.config.language.ja.latestTemplateOptions;
                // Re-order feeds for latest tab
                for (var key in this.latestTemplateOptions) {
                    // Set the latest template options blocks size
                    this.latestTemplateOptions[key].size = this.config.layout.getColumnsSize(this.latestTemplateOptions[key].size);

                    // Use the same loop to set the default template options blocks size
                    this.defaultTemplateOptions[key].size = this.config.layout.getColumnsSize(this.defaultTemplateOptions[key].size);
                    for (var i = 0; i < socialMedia.length; i++) {
                        if (socialMedia[i].id === key) {
                            this.tabsFeeds[socialMedia[i].id] = socialMedia[i];
                            this.tabsFeeds[socialMedia[i].id].channelUrl = this.config.channelUrl[socialMedia[i].id];
                            this.tabsFeeds[socialMedia[i].id].resources = this.resources;
                        }
                        if (!tabsSet && socialMedia[i].feed.length > 0) {
                            this.setTab(socialMedia[i]);
                        }
                        if (i === socialMedia.length - 1) {
                            tabsSet = true;
                        }
                    }
                }
                this.postProcessFeeds();
                this.startTabs();
            },

            enumerable: false,
            writable: true
        },

        setTab: {
            value: function(tab) {
                var temp = {
                    id: tab.id,
                    title: tab.title
                };
                this.tabs.items.push(temp);
            },

            enumerable: false,
            writable: true
        },

        getData: {
            value: function(dataUrl) {
                return this.pagetools.window._element[0].$.ajax(dataUrl);
            },

            enumerable: false,
            writable: true
        },

        postProcessFeeds: {
            value: function(singleItem) {
                var feeds = singleItem ? this.singleFeed : this.tabsFeeds,
                    _processFeedData = function(data, callback) {
                        if (data && callback) {
                            for (var i = 0; i < data.length; i++) {
                                callback.call(this, data, i);
                            }
                        }
                    }.bind(this);

                for (var key in feeds) {
                    switch (key) {
                        case "twitter": {
                            var twitterData = feeds[key].feed;

                            _processFeedData(twitterData, function(data, i) {
                                data[i].createdDate = data[i].Link.Date;
                            });
                            break;
                        }
                        case "facebook": {
                            var facebookData = feeds[key].feed;

                            _processFeedData(facebookData, function(data, i) {
                                if (data[i].hasOwnProperty("created_time")) {
                                    data[i].createdDate = this.parseDate(data[i].created_time);

                                    if (data[i].created_time.length < 10) {
                                        data[i].createdDate = data[i].created_time;
                                    }
                                }
                            }.bind(this));
                            break;
                        }
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        parseDate: {
            value: function(date) {
                var _Date = this.pagetools.window._element[0].Date,
                    newDate = new _Date(date.replace(/\+.*/, "")),
                    dateArray = [];

                // "Thu Nov 27 2014"
                newDate = newDate.toDateString();
                dateArray = newDate.split(" ");

                return dateArray[1] + " " + dateArray[2];
            },

            enumerable: false,
            writable: true
        },

        startTabs: {
            value: function() {
                var tabsTemplate = this.Templates._tabs(this.tabs);

                view.$.append(tabsTemplate);

                this.tabsConfig = {
                    scope: view.$,
                    tabSet: view.$.find(".helper-tabs.level-1"),
                    tabContentSet: view.$.find(".helper-tabs.level-2"),
                    mobileAsDropdown: false, // This module doesn't have tabs on mobile - Always keep this as false and don't remove it, because default is true, unless you need to render the tabs on mobile.
                    onTabInit: function(index, content) {
                        this.addTabContent(index, content);
                    }.bind(this),
                    onTabClick: function(index, content) {
                        $(content).find(".item").each(function(index, element) {
                            var $element = $(element);
                            this.clampLines($element);
                        }.bind(this));
                    }.bind(this)
                };
                new (Helpers("tabs"))(this.tabsConfig);
            },

            enumerable: false,
            writable: true
        },

        addTabContent: {
            value: function(index, content) {
                var tabIndex = index,
                    $tabContent = content,
                    currentTab = this.tabs.items[tabIndex].id,
                    tabHtml;
                if (currentTab === "latest") {
                    var templateOptions = this.latestTemplateOptions;
                    tabHtml = this.renderTemplate (this.tabsFeeds, templateOptions);
                    // Creates rows of items for the latest tab template
                    var itemsPerRow = this.siteLanguage("en") ?
                                      this.config.layout.itemsPerRow.base :
                                      this.config.layout.itemsPerRow.latest;


                    tabHtml = this.wrapItems(tabHtml, itemsPerRow);
                } else {
                    var jsonFeed = {};
                    jsonFeed[currentTab] = this.tabsFeeds[currentTab];
                    tabHtml = this.renderTemplate (jsonFeed, this.defaultTemplateOptions);
                    // 3 column layout
                    tabHtml = this.wrapItems(tabHtml);
                }

                if (tabHtml) {
                    $tabContent.html(tabHtml);
                }
                // Layout adjustments
                $tabContent.find(".item").each(function(index, element) {
                    var $element = $(element);
                    this.checkImagesLoaded($element, [this.itemContentOffset, this.clipText]);
                }.bind(this));

                var latestTranslation = view.$.attr("data-translation"),
                    latestTab = view.$.find(".helper-tabs.level-1 a.default"),
                    json;
                if(typeof latestTranslation !== "undefined"){
                    json = jQuery.parseJSON(latestTranslation);
                    latestTab.html(json["latest"]);
                }
            },

            enumerable: false,
            writable: true
        },

        renderTemplate: {
            value: function(list, options) {
                var tabHtml = "";

                for (var key in list) {
                    list[key].options = options ? options[key] : this.defaultTemplateOptions[key];
                    var templateName = "_" + key;
                    tabHtml += this.Templates[templateName].call(this, list[key]);
                }

                return tabHtml;
            },

            enumerable: false,
            writable: true
        },

        wrapItems: {
            value: function(template, every) {
                var scope = $(template).filter("div"),
                    everyItems = every || this.config.layout.itemsPerRow.base,
                    everyItemsLength = everyItems.length > 0 ? everyItems.length : 1 ,
                    singleRow = everyItems.length > 0 ? true : false ,
                    everyItems = everyItems.length > 0 ? everyItems : [everyItems] ,
                    rowTemplate = "<div class=\"layout\"><div class=\"container\">{{innerHtml}}</div></div>",
                    newHtml = "",
                    outerCounter = 0,
                    prevCount = everyItems[0],
                    mapHtml = function(items) {
                        var html = items.map(function () {
                            return this.outerHTML;
                        }).get().join("");

                        return html;
                    };

                for(var i = 0; i < everyItemsLength; i++){
                    for (var counter = outerCounter ; counter < scope.length; counter += prevCount) {
                        var $itemSet = scope.slice(counter, counter + everyItems[i]),
                            setHtml = "";
                        prevCount = everyItems[i];
                        outerCounter = counter + prevCount;
                        $itemSet.last().addClass("last-child");
                        setHtml = mapHtml($itemSet);
                        newHtml += rowTemplate.replace("{{innerHtml}}", setHtml);

                        if(singleRow)
                            break;
                    }
                }

                return newHtml;
            },

            enumerable: false,
            writable: true
        },

        itemContentOffset: {
            value: function($scope) {
                var $content = $scope.find(".content"),
                    $image = $scope.find(".image");

                if (!!$image.length && !$scope.is("[class*=\"cols-" + this.config.layout.wide + "\"]")) {
                    var scopeHeight = $scope.outerHeight(true),
                        imageHeight = $image.height(),
                        contentOffset = (imageHeight * 100) / scopeHeight;

                    $content.css("top", contentOffset + "%");
                }
            },

            enumerable: false,
            writable: true
        },

        clampLines: {
            value: function(scope) {
                var $scope = $(scope),
                    $content = $scope.find(".content"),
                    $description = $scope.find(".description"),
                    $title = $scope.find(".category"),
                    $details = $scope.find(".details"),
                    $text = $description.find("p"),
                    $readMore = $scope.find(".read-more-link");

                if (!!$text.length) {
                    // Divides the height by the number of lines and rounds down to ensure half lines are cut off, then multiplies it by the line-height again to give the final height of the box.
                    var titleHeight = $title.outerHeight(true) || 0,
                        contentHeight = $content.outerHeight(true) || 0,
                        contentPadding = parseInt($content.css("paddingTop").replace("px","")) + parseInt($content.css("paddingBottom").replace("px","")) || 0,
                        descriptionHeight = $description.outerHeight(true) || 0,
                        detailsHeight = $details.outerHeight(true) || 0,
                        readMoreHeight = $readMore.outerHeight(true) || 0,
                        copyLineH = parseInt($description.find("p").first().css("line-height").replace("px","")), // The line-height of the description text
                        availableH = contentHeight - titleHeight - detailsHeight - contentPadding - readMoreHeight, // Calculates the available height for the descriptive text
                        adjustH = (Math.floor(availableH/copyLineH) * copyLineH);

                    // Set the target height as per calculations
                    if ($text.outerHeight(true) > availableH) {
                        if (!$content.find(".more-text").length) {
                            if(!$content.find(".more-text-description").length){
                                $content.append("<span class=\"more-text\">...</span>");
                            }
                        }
                        $description.height(adjustH);
                        $content.addClass("ellipsis");
                    } else {
                        $content.removeClass("ellipsis");
                        $description.css("height", "");
                    }
                    if ($description.height() === 0) {
                        $content.addClass("ellipsis-hidden");
                    } else {
                        $content.removeClass("ellipsis-hidden");
                    }
                }

                if($content.closest(".item").hasClass("blog")){
                    var avalZoomZoomHeight = contentHeight - titleHeight - contentPadding - readMoreHeight;
                    var  detailsLineHeight = parseInt($details.find("p").first().css("line-height").replace("px",""));
                    var adjH = (Math.floor(avalZoomZoomHeight/detailsLineHeight) * detailsLineHeight);
                    if(adjH > 10 && detailsHeight > avalZoomZoomHeight){
                        $details.css({
                            height: adjH,
                            overflow: "hidden"
                    });
                        if(!$content.find(".more-text-description").length){
                            if(adjH >= 20){
                                $content.append("<span class=\"more-text-description\">...</span>");
                            }
                            $content.find(".more-text").remove();
                        }
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        clipText: {
            value: function(scope) {
                var overflow = function(element){
                    if (element.prop("clientHeight") < element.prop("scrollHeight")) {
                        return true;
                    } else {
                        return false;
                    }
                };
                this.clampLines(scope);
                this.pagetools.window.on("resize", function(event) {
                    this.clampLines(scope);
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        checkImagesLoaded: {
            value: function(scope, callbackQueue) {
                var loadCounter = 0,
                    $images = scope.find("img"),
                    _startCallback = function() {
                        if (!!callbackQueue.length) {
                            for (var i = 0; i < callbackQueue.length; i++) {
                                callbackQueue[i].call(this, scope);
                            }
                        }
                    }.bind(this);

                if (!!$images.length) {
                    $images.each(function(i, item) {
                        $(item).load(function() {
                            loadCounter ++;
                            if (loadCounter === $images.length) {
                                _startCallback();
                            }
                        });
                    });
                } else {
                    _startCallback();
                }
            },

            enumerable: false,
            writable: true
        },

        siteLanguage: {
            value: function(language) {
                return this.$body.hasClass(language);
            },

            enumerable: false,
            writable: true
        }
    });

    return SocialMedia;
}();

return SocialMedia;
});
}).apply(window);/**!!<[ModuleSocialMedia_com]!!**/
/**!![ModulePrimaryNavigation]>!!**/
(function(){
registerModule("ModulePrimaryNavigation", "core", function() {
var Menu = function() {
    "use strict";

    function Menu() {
        console.log('module.primary-navigation constructor test');
    }

    return Menu;
}();

return Menu;
});
}).apply(window);/**!!<[ModulePrimaryNavigation]!!**/
/**!![ModuleSecondaryNavigation]>!!**/
(function(){
registerModule("ModuleSecondaryNavigation", "core", function() {
var $__Object$defineProperties = Object.defineProperties;

var SecondaryNavigation = function() {
    "use strict";

    function SecondaryNavigation(config) {
        // Scope mapping
        this.$scope = view.$;

        // Set menu state control variable
        this.secondLevelIn = true;

        // Initialise the menu
        // TODO: remove setTimeout
        setTimeout(function() {
            this.init.call(this, Services('pagetools'));
        }.bind(this));
    }

    $__Object$defineProperties(SecondaryNavigation.prototype, {
        init: {
            value: function(pagetools) {
                // TODO: move below line to constructor once setTimeout is removed
                this.pagetools = pagetools;

                this.$window = this.pagetools.window._element[0];

                // Define the navigation's first level
                this.$firstLevel = this.$scope.find('nav');
                this.$firstLevelItems = this.$firstLevel.find('ul.level-1').children('li');
                this.$firstLevelLinks = this.$firstLevelItems.children('a');

                this.initDesktop();
            },

            enumerable: false,
            writable: true
        },

        initDesktop: {
            value: function() {
                // Map all nodes
                this.mapNodes();

                // Store the currently selected item
                this.$selectedItem = this.$firstLevelItems.filter('.selected');

                this.$firstLevelFullItems = $();

                this.$firstLevelItems.each(function(index, element) {
                    var item = $(element);
                    if(item.find('> ul').length) this.$firstLevelFullItems = this.$firstLevelFullItems.add(item);
                    else item.addClass('last-level');
                }.bind(this));

                var accordionConfig = {
                    $container:this.$scope.find('.container'),
                    selectors : {
                        accordion:"nav",
                        accordionItem:".level-1 > li",
                        accordionItemThumb:"> a",
                        accordionItemContent:"> .level-2"
                    },
                    selection:function($element, status) {
                        $element[status?"addClass":"removeClass"]("active");
                    }/*,
                    isSelected:function($element){
                        return $element.data("selected");
                    }*/
                }
                var dropdownConfig = {
                    $container:this.$scope,
                    selectors : {
                        accordion:".container",
                        accordionItem:"nav",
                        accordionItemThumb:"> .current",
                        accordionItemContent:"> .level-1"
                    },
                    selection:function($element, status) {
                        $element[status?"addClass":"removeClass"]("active");
                    }
                }

                var accordionInstance = new (Helpers('accordion'))(accordionConfig);
                new (Helpers('accordion'))(dropdownConfig);

                if (this.$window.matchMedia('screen and (min-width: 768px)').matches) {
                    accordionInstance.unbindEvents();
                    this.moveSecondLevelOut();
                }
                $(this.$window).on('resize',function() {
                    if (this.secondLevelIn && this.$window.matchMedia('screen and (min-width: 768px)').matches) {
                        accordionInstance.unbindEvents();
                        this.moveSecondLevelOut();
                    }else if(!this.secondLevelIn && this.$window.matchMedia('screen and (max-width: 768px)').matches){
                        this.moveSecondLevelIn();
                        accordionInstance.bindEvents();
                    }
                }.bind(this))

                // Handler for first level click event
                // Quick fix for desktop nav
                /*this.$firstLevelLinks.on('click', (e) => {
                    if (this.$window.matchMedia('screen and (min-width: 768px)').matches) {
                        var $item = $(e.currentTarget).parent('li'),
                            itemId = $item.attr('data-id'),
                            $secondLevel = this.$scope.find('.level-2[data-parent-id="' + itemId + '"]'),
                            $secondLevelItems = $secondLevel.children('li');

                        if ($secondLevel.length) {
                            e.preventDefault();

                            var templateId = $secondLevel.attr('data-template-id'),
                                collectionId = $secondLevel.attr('data-collection-id');

                            if (templateId && this.processTemplate) {       // Override default content
                                var urlMapping = {};

                                $secondLevelItems.children('a').each((index, element) => {
                                    var $element = $(element),
                                        id = $element.attr('data-id'),
                                        url = $element.children('a').attr('href');

                                    urlMapping[id] = url;
                                });

                                this.processTemplate.call(this,
                                    templateId,
                                    collectionId,
                                    $secondLevel,
                                    urlMapping
                                );

                                $secondLevel.removeAttr('data-template-id');
                            }
                            this.toggle($item);
                        }
                    }
                });*/
            },

            enumerable: false,
            writable: true
        },

        mapNodes: {
            value: function(indexMap, $nodeList) {
                indexMap = indexMap || [1];
                $nodeList = $nodeList || this.$firstLevel.children();

                for (var i = 0; i < $nodeList.length; i++) {
                    var $node = $($nodeList[i]);

                    if ($node.prop('tagName') === 'UL') {
                        $node.attr('data-parent-id', indexMap.join('.'));

                        if ($node.children('li').length) {
                            indexMap.push(1);

                            this.mapNodes(indexMap, $node.children('li'));

                            indexMap.pop();
                        }
                    } else if ($node.prop('tagName') === 'LI') {
                        $node.attr('data-id', indexMap.join('.'));

                        if ($node.children('ul').length) {
                            this.mapNodes(indexMap, $node.children('ul'));
                        }

                        indexMap[indexMap.length - 1]++;
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        moveSecondLevelOut: {
            value: function() {
                this.$scope.find('nav').append(this.$scope.find('.level-2'));

                this.secondLevelIn = false;
            },

            enumerable: false,
            writable: true
        },

        moveSecondLevelIn: {
            value: function() {
                this.$firstLevelItems.each(function(index, element) {
                    var $item = $(element),
                        itemId = $item.attr('data-id'),
                        $secondLevel = this.$scope.find('.level-2[data-parent-id="' + itemId + '"]');

                    if ($secondLevel.length) {
                        $item.append($secondLevel);
                    }
                }.bind(this));

                this.secondLevelIn = true;
            },

            enumerable: false,
            writable: true
        },

        toggle: {
            value: function($item) {
                if (!this.$window.matchMedia('screen and (max-width: 768px)').matches) {
                    var itemId = $item.attr('data-id'),
                        $secondLevel = this.$scope.find('.level-2[data-parent-id="' + itemId + '"]'),
                        $browseItem = this.$firstLevelItems.filter('.browse'),
                        browseItemId = $browseItem.attr('data-id'),
                        $browseItemSecondLevel = this.$scope.find('.level-2[data-parent-id="' + browseItemId + '"]');

                    if ($browseItem && !$browseItem.is($item)) {
                        $browseItem.removeClass('browse');
                        $browseItemSecondLevel.removeClass('active');
                    }

                    if ($item.hasClass('browse')) {
                        $item.removeClass('browse');
                        $secondLevel.removeClass('active');
                        this.$selectedItem.removeClass('dim');
                    } else {
                        $item.addClass('browse');
                        $secondLevel.addClass('active');
                        if (!$item.hasClass('selected')) {
                            this.$selectedItem.addClass('dim');
                        }
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        toggleScroll: {
            value: function() {
                var $body = this.pagetools.body._element,
                    $content = this.pagetools.content._element;

                if ($body.hasClass('disable-overflow')){
                    $content.removeClass('disable-overflow');
                    $body.removeClass('disable-overflow');
                } else {
                    $content.addClass('disable-overflow');
                    $body.addClass('disable-overflow');
                }
            },

            enumerable: false,
            writable: true
        }
    });

    return SecondaryNavigation;
}();

return SecondaryNavigation;
});
}).apply(window);/**!!<[ModuleSecondaryNavigation]!!**/
/**!![ModuleFooter]>!!**/
(function(){
registerModule("ModuleFooter", "core", function() {
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */
});
}).apply(window);/**!!<[ModuleFooter]!!**/
/**!![ModuleSitemap]>!!**/(function(){"use strict";Modules.registerModule("ModuleSitemap","",function(){})}).apply(window);/**!!<[ModuleSitemap]!!**/
/**!![ModulePurchaseToolMenu]>!!**/(function(){"use strict";Modules.registerModule("ModulePurchaseToolMenu","",function(){})}).apply(window);/**!!<[ModulePurchaseToolMenu]!!**/
/**!![ModuleFooterSubNavigation]>!!**/
(function(){
registerModule("ModuleFooterSubNavigation", "core", function() {
"use strict";
});
}).apply(window);/**!!<[ModuleFooterSubNavigation]!!**/
/**!![ModuleGlobalNavigation_com]>!!**/
(function(){
registerModule("ModuleGlobalNavigation", "com", function() {
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */

var $__Object$defineProperties = Object.defineProperties;

var GlobalNavigation = function() {
    "use strict";

    function GlobalNavigation() {
        setTimeout(function() {
            this.pagetools = Services("pagetools");
            this.init();
        }.bind(this));
    }

    $__Object$defineProperties(GlobalNavigation.prototype, {
        init: {
            value: function() {
                this.$body = this.pagetools.body._element;
                this.$body.find(".module-global-navigation").on("touchstart click", "a", function(e) {
                    e.stopPropagation();
                });
            },

            enumerable: false,
            writable: true
        }
    });

    return GlobalNavigation;
}();

return GlobalNavigation;
});
}).apply(window);/**!!<[ModuleGlobalNavigation_com]!!**/
/**!![ModulePrimaryNavigation_com]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_promos"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression, buffer = "	<div class=\"promo\">\n        <div class=\"image\" style=\"background-image: url('"
    + escapeExpression(lambda((depth0 != null ? depth0.thumbnail : depth0), depth0))
    + "')\">\n            <img src=\""
    + escapeExpression(lambda((depth0 != null ? depth0.thumbnail : depth0), depth0))
    + "\" alt=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\">\n        </div>\n        <div class=\"content\">\n            <h3 class=\"title\">"
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "</h3>\n            <div class=\"description\">\n                ";
  stack1 = lambda((depth0 != null ? depth0.description : depth0), depth0);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "\n            </div>\n            <a title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.destinationText : depth0), depth0))
    + " "
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" class=\"promos-link\" href=\""
    + escapeExpression(lambda((depth0 != null ? depth0.destinationUrl : depth0), depth0))
    + "\">"
    + escapeExpression(lambda((depth0 != null ? depth0.destinationText : depth0), depth0))
    + "<span class=\"ic\"></span></a>\n        </div>\n    </div>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"navigation-promos\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</div>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('ModulePrimaryNavigation.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerModule("ModulePrimaryNavigation", "com", function() {
/*
 * @module PrimaryNavigation
 */

/**
 * @name moduleConfig
 * @description Configuration object for PrimaryNavigation
 * @type {object}
 */
var $__Object$defineProperty = Object.defineProperty;
var $__Object$create = Object.create;
var $__Object$getPrototypeOf = Object.getPrototypeOf;
var $__Object$defineProperties = Object.defineProperties;
var moduleConfig = {
        selectedClass: "selected",
        level1Class: "level-1",
        level2Class: "level-2"
    };

// TEMP FIXES
view.$.children(".level-1").addClass("clearfix");
view.$.find("a").removeAttr("data-id");

var Menu = function() {
    "use strict";

    function Menu() {
        // Scope mapping
        this.$scope = view.$;
        this.lockMobileNav = false;

        // Define the navigation's first level
        this.$firstLevel = this.$scope.children(".level-1");

        // Hack
        if (!this.$firstLevel.length) {
            this.$firstLevel = this.$scope;
        }

        this.$firstLevelItems = this.$firstLevel.children("li");

        // Store the currently selected item
        this.$selectedItem = this.$firstLevelItems.filter(".selected");

        this.$selectedItem.addClass("browse").removeClass("selected");

        // Map all nodes
        this.mapNodes();

        // Initialise the menu
        this.init();
        //find /ja/careers/
        var careersLink =  view.$.find("a[href$=\"/ja/careers/\"]").first(),
            newsLink = view.$.find("a[href$=\"/en/news/\"]").first();

        careersLink.parent().addClass("right-align");
        newsLink.parent().addClass("promo-padding-19");
    }

    $__Object$defineProperties(Menu.prototype, {
        mapNodes: {
            value: function(indexMap, $nodeList) {
                indexMap = indexMap || [1];
                $nodeList = $nodeList || this.$firstLevel.children();

                for (var i = 0; i < $nodeList.length; i++) {
                    var $node = $($nodeList[i]),
                        $nodeChildrenLi = $node.find("li");

                    if ($node.prop("tagName") === "UL" || $node.prop("tagName") === "DIV") {
                        $node.attr("data-parent-id", indexMap.join("."));

                        if ($nodeChildrenLi.length) {
                            indexMap.push(1);

                            this.mapNodes(indexMap, $nodeChildrenLi);

                            indexMap.pop();
                        }
                    } else if ($node.prop("tagName") === "LI") {
                        $node.attr("data-id", indexMap.join("."));

                        if ($node.children("ul").length || $node.children("div").length) {
                            this.mapNodes(indexMap, $node.children(".level-2"));
                        }

                        indexMap[indexMap.length - 1]++;
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        init: {
            value: function() {
                // Handler for first level click event
                // this.$firstLevelItems.children('a').on('click mouseover', 'span', (e) => {
                this.$firstLevelItems.children("a").on("click mouseover", function(e) {
                    e.preventDefault();
                    e.stopPropagation();


                    if(!(this.isMobile() && e.type=="mouseover")) // stop mouseover fireing on mobile
                    {
                        var $item = $(e.currentTarget).parent(),
                            itemId = $item.attr("data-id"),
                            $secondLevel = this.$scope.find(".level-2[data-parent-id=\"" + itemId + "\"]"),
                            $secondLevelItems = $secondLevel.children("li"),
                            url = $item.children("a").first().attr("href");
                        if ($secondLevel.length) {
                            // Override default link behaviour
                            if($item.hasClass("browse")){
                                if(!this.isMobile()) {
                                    if(e.type == "click" || e.type == "touchend")
                                        this._window.location.href = url;
                                }else {
                                    $item.removeClass("browse");
                                }
                            }else{
                                e.preventDefault();
                                this.toggle($item);
                            }
                        }else {
                            //close previous panel as this item doesnt have second level
                            var $browseItem = this.$firstLevelItems.filter(".browse"),
                            browseItemId = $browseItem.attr("data-id"),
                            $browseItemSecondLevel = this.$scope.find(".level-2[data-parent-id=\"" + browseItemId + "\"]");
                            $browseItem.removeClass("browse");
                            $browseItemSecondLevel.hide();

                            if(e.type == "click" || e.type == "touchend")
                                this._window.location.href = url;
                        }
                    }
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        toggle: {
            value: function($item) {
                var itemId = $item.attr("data-id"),
                    $secondLevel = this.$scope.find(".level-2[data-parent-id=\"" + itemId + "\"]"),
                    $browseItem = this.$firstLevelItems.filter(".browse"),
                    browseItemId = $browseItem.attr("data-id"),
                    $browseItemSecondLevel = this.$scope.find(".level-2[data-parent-id=\"" + browseItemId + "\"]");

                if ($browseItem && !$browseItem.is($item)) {
                    $browseItem.removeClass("browse");
                    $browseItemSecondLevel.hide();
                }

                if ($item.hasClass("browse")) {
                    $item.removeClass("browse");
                    $secondLevel.hide();
                    this.$selectedItem.removeClass("dim");
                } else {
                    $item.addClass("browse");
                    if(this.isMobile()){
                        $secondLevel.show();
                    }else{
                        $secondLevel.slideDown();
                    }
                    if (!$item.hasClass("selected")) {
                        this.$selectedItem.addClass("dim");
                    } else {
                        this.$selectedItem.removeClass("dim");
                    }
                }
            },

            enumerable: false,
            writable: true
        }
    });

    return Menu;
}();

var ComPrimaryNavigation = function($__super) {
    "use strict";

    function ComPrimaryNavigation() {
        $__Object$getPrototypeOf(ComPrimaryNavigation.prototype).constructor.call(this);
        setTimeout(function() {
            this.navigationConfig = {
                level2ColumnItems: 7
            };
            this.pagetools = Services("pagetools");
            this.initNavigation();
        }.bind(this));
    }

    ComPrimaryNavigation.__proto__ = ($__super !== null ? $__super : Function.prototype);
    ComPrimaryNavigation.prototype = $__Object$create(($__super !== null ? $__super.prototype : null));

    $__Object$defineProperty(ComPrimaryNavigation.prototype, "constructor", {
        value: ComPrimaryNavigation
    });

    $__Object$defineProperties(ComPrimaryNavigation.prototype, {
        initNavigation: {
            value: function() {
                try {
                    this.$window = this.pagetools.window._element;
                    this._window = this.$window[0];
                    this.$header = this.pagetools.header._element;
                    this.$body = this.pagetools.body._element;
                    this._document = this._window.document;
                    this.$html = $(this._document).find("html");
                    this.navigationConfig["translations"] = view.$.data("translations");
                    this.$navigationWrapper = view.$.parent();
                    this.navigationWidth = 0;
                    this.Templates = {
                        _promos: Services("templateService").templates("ModulePrimaryNavigation._promos")
                    };

                    if (!this.isMobile()) {
                        this.collapsedNavigation();
                        this.navOverlay("remove");
                    } else {
                        this.addMobileButton();
                    }

                    this.bindEvents();
                    this.postProcessSecondLevel();
                    this.afterMenuBuild();
                } catch(e) {
                    console.log(e.toString());
                    view.$.addClass("loaded");
                }
            },

            enumerable: false,
            writable: true
        },

        bindEvents: {
            value: function() {
                this.$header.off("click", ".mobile-navigation-button");
                this.$header.on("click", ".mobile-navigation-button", function(e) {
                    e.stopPropagation();

                    if(!this.lockMobileNav) {
                        this.toggleMobile(this.$header);
                        this.lockMobileNav = true;
                    }
                }.bind(this));
                this.pagetools.window.on("resize", function() {
                    if (this.isMobile()) {
                        this.addMobileButton();
                        this.navOverlay("remove");
                    }
                    this.collapsedNavigation();
                    this.resizeCollapsedNavigation();
                }.bind(this));

                view.$.on("mouseleave", function(e) {
                    if(!this.isMobile())
                        this.closeNav();
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        postProcessSecondLevel: {
            value: function() {
                this.$firstLevelItems.each(function(i, item) {
                    var $this = $(item),
                        $level2 = $this.find(".level-2"),
                        $level2List = $level2.find("ul"),
                        _reAlignLevel2 = function() {
                            var windowWidth = this.$window[0].innerWidth ||
                                              this.$window[0].document.documentElement.clientWidth ||
                                              this.$window[0].document.body.clientWidth,
                                viewWidth = view.$.outerWidth(true),
                                level2Width = $level2.outerWidth(true),
                                $thisOffset = $this.offset(),
                                availableWidth = viewWidth - ($thisOffset.left - ((windowWidth - viewWidth) / 2));

                            if (level2Width > availableWidth) {
                                $this.addClass("children-align-right");
                            }
                        }.bind(this);


                    if ($level2.length > 0) {
                        $this.addClass("has-children");

                        if ($level2List.children().length > this.navigationConfig.level2ColumnItems) {
                            this.makeColumnsList($level2List, this.navigationConfig.level2ColumnItems);
                        }
                        if (!!$level2.data("service")) {
                            $level2.addClass("has-promos");
                        } else {
                            _reAlignLevel2();
                        }
                    }
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        collapsedNavigation: {
            value: function() {
                var $level1Children = this.$firstLevel.children(),
                    navigationAllowedWidth = this.$navigationWrapper.width() - this.$navigationWrapper.find(".module-language-selector").outerWidth(true);

                if (!this.navigationWidth && !this.isMobile()) {
                    $level1Children.each(function(index, item) {
                        this.navigationWidth += $(item).outerWidth(true);
                    }.bind(this));
                }

                if (this.navigationWidth >= navigationAllowedWidth && !this.isMobile()) {
                    if (!view.$.hasClass("collapsed")) {
                        view.$.addClass("collapsed");
                        if (!this.$firstLevel.find(".browse").length) {
                            this.$firstLevel.addClass("hidden");
                        }
                        this.$navigationWrapper.addClass("collapsed-navigation");
                        if (!view.$.find(".open-collapsed-menu").length) {
                            $("<button class=\"open-collapsed-menu\">Menu</button>").prependTo(view.$).on("click", function(e) {
                                this.$firstLevel.toggleClass("hidden");
                                this.navOverlay("toggle");
                                this.windowEvent("add", "click.collapsedNavOutside touchstart.collapsedNavOutside", function() {
                                    this.$firstLevel.toggleClass("hidden");
                                    this.navOverlay("remove");
                                    this.windowEvent("remove", "click.collapsedNavOutside touchstart.collapsedNavOutside");
                                }.bind(this));
                            }.bind(this));
                        }
                    }
                } else {
                    if (view.$.hasClass("collapsed")) {
                        view.$.removeClass("collapsed");
                        this.windowEvent("remove", "click.collapsedNavOutside");
                        this.$navigationWrapper.removeClass("collapsed-navigation");
                        this.$firstLevel.removeClass("hidden");
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        afterMenuBuild: {
            value: function() {
                view.$.addClass("loaded");
                this.$currentPageItem = this.$firstLevel.find(".selected");

                this.$firstLevelItems.children("a").on("click mouseover touchend", function(e) {
                    var $targetParent = $(e.currentTarget).parent();
                    if (!this.isMobile()) {
                        this.windowEvent("remove", "click.navOutside");
                    }
                    if ($targetParent.hasClass("has-children") && !this.isMobile()) {
                        if (!view.$.hasClass("collapsed")) {
                            if (!this.isMobile()) {
                                this.navOverlay("add");
                            }
                        }
                        _renderPromos($targetParent);
                    }
                }.bind(this));

                var _renderPromos = function($scope) {
                    var $item = $scope.find(".level-2"),
                            $navigationPromos = $item.find(".navigation-promos"),
                            getPromos = $navigationPromos.length < 1 &&
                                        !!$item.hasClass("has-promos") &&
                                        !this.isMobile(),
                             _cropOnResize = function() {
                                 this.$window.on("resize.navPromos", function(event) {
                                     this.cropPromos($item);
                                 }.bind(this));
                             }.bind(this);

                    if ($item.parent().hasClass("browse") && !this.$firstLevel.hasClass("hidden") && !this.isMobile()) {
                        if ($item.hasClass("promos-rendered")) {
                            this.cropPromos($item);
                            _cropOnResize();
                        } else if (getPromos) {
                            $item.addClass("promos-rendered");
                            _cropOnResize();
                            this.getPromos($item);
                        }
                    } else {
                        this.$window.off("resize.navPromos");
                        this.windowEvent("remove", "click.navOutside touchstart.navOutside");
                        if (!view.$.hasClass("collapsed") && !this.isMobile()) {
                            this.navOverlay("remove");
                        }
                    }

                    this.resizeCollapsedNavigation($item);
                }.bind(this);
            },

            enumerable: false,
            writable: true
        },

        resizeCollapsedNavigation: {
            value: function($scope) {
                var $item = $scope || view.$.find(".browse").find(".level-2"),
                    $itemChildrenWrapper = $item.find(".list-wrapper"),
                    _resetNavigation = function() {
                        $itemChildrenWrapper.height("");
                        this.$firstLevel.height("");
                    }.bind(this);

                _resetNavigation();
                if (view.$.hasClass("collapsed")) {
                    if ($item.parent().hasClass("browse")) {
                        this.$firstLevel.css("width","100%");
                        var childrenWrapperHeight = $itemChildrenWrapper.height(),
                            firstLevelHeight = this.$firstLevel.height();

                        if (childrenWrapperHeight > firstLevelHeight) {
                            this.$firstLevel.height(childrenWrapperHeight);
                        } else {
                            $itemChildrenWrapper.height(firstLevelHeight);
                        }
                    } else {
                        this.$firstLevel.css("width", "auto");
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        getPromos: {
            value: function($scope) {
                var apiLocation = $scope.data("service"),
                    windowProtocol = this._window.location.protocol,
                    windowHost = this._window.location.host,
                    apiUrl = windowProtocol + "//" + windowHost + "/" + apiLocation;

                this.getData(apiUrl)
                    .done(function(data) {
                    this.renderPromos($scope, data);
                }.bind(this))
                    .fail(function(data) {
                    console.log("Promos request failed: " + data);
                });
            },

            enumerable: false,
            writable: true
        },

        renderPromos: {
            value: function($scope, data) {
                var temp = {
                        items: data
                    },
                    promosHtml = this.Templates._promos(temp);

                $scope.append(promosHtml);
                this.checkImagesLoaded($scope, this.cropPromos);
            },

            enumerable: false,
            writable: true
        },

        cropPromos: {
            value: function($scope) {
                var scopeWidth = $scope.width(),
                    $list = $scope.find(".list-wrapper"),
                    $promos = $scope.find(".navigation-promos"),
                    promosVisibleWidth = scopeWidth - $list.outerWidth(true),
                    singlePromoWidth = $promos.find(".promo").first().outerWidth(true),
                    visiblePromos = Math.floor(promosVisibleWidth / singlePromoWidth) || 0;

                $promos.children().each(function(i, item) {
                    if (i + 1 > visiblePromos) {
                        $(item).removeClass("visible");
                    } else {
                        $(item).addClass("visible");
                    }
                });
            },

            enumerable: false,
            writable: true
        },

        getData: {
            value: function(url) {
                return this.$window[0].$.ajax(url);
            },

            enumerable: false,
            writable: true
        },

        addMobileButton: {
            value: function() {
                //console.log(this.$header.find('.mobile-navigation-button').length);
                if (this.$header.find(".mobile-navigation-button").length < 1) {
                    var mobileButton = $("<button class=\"mobile-navigation-button\" />");
                    //view.$.parent().before(mobileButton);
                    this.$header.append(mobileButton);
                }
            },

            enumerable: false,
            writable: true
        },

        toggleMobile: {
            value: function() {
                if (this.isMobile()) {
                    if (this.$body.hasClass("open-main-nav")) {
                        this.$body.removeClass("open-main-nav");
                        this.$body.removeClass("disable-scroll");
                        this.navOverlay("remove");
                        this.windowEvent("remove", "click.navOutside touchstart.navOutside");
                        var that = this;
                        setTimeout(function(){
                            that.lockMobileNav = false;
                        },1000);
                    } else {
                        this.$body.addClass("open-main-nav");
                        this.$body.addClass("disable-scroll");
                        this.navOverlay("add");
                        this.windowEvent("add", "click.navOutside touchstart.navOutside", function(e, target) {
                            if($(target).hasClass("main-header")) return;
                            this.toggleMobile();
                        }.bind(this), view.$.parent());
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        isMobile: {
            value: function() {
                return this.$window[0].innerWidth < 965;
            },

            enumerable: false,
            writable: true
        },

        checkImagesLoaded: {
            value: function($scope, callback) {
                var loadCounter = 0,
                    $contentImages = $scope.find("img");

                if ($contentImages.length > 0) {
                    $contentImages.each(function(i, item) {
                        while (loadCounter < $contentImages.length) {
                            var $item = $(item);
                            if (!!$item.attr("src")) {
                                $item.load(function() {});
                            }
                            loadCounter ++;
                        }
                        callback.call(this, $scope);
                    }.bind(this));
                } else {
                    callback.call(this, $scope);
                }
            },

            enumerable: false,
            writable: true
        },

        makeColumnsList: {
            value: function($list, maxColumnItems) {
                // Turns a raw list into columns
                var listClassName = $list.attr("class"),
                    $listItems = $list.children(),
                    itemsCount = $listItems.length,  //counts the number of elements in the whole list
                    columns = Math.ceil(itemsCount / maxColumnItems);

                if ($list) {
                    for (var i = 1; i < columns + 1; i++) {
                        //creates the ul's that are gone act as columns
                        $list.parent().append($("<ul class=\"level-2-list column-"+ i +"\"></ul>"));
                    }

                    $listItems.each(function(i, item) {
                        //iterates throught the list
                        var $this = $(item);
                        //appends the elements to the ul, based on the number of elements per column
                        $list.parent().find(".column-" + (1 + Math.floor(i / maxColumnItems))).append($this);
                    });

                    //removes the raw list
                    $list.remove();
                }
            },

            enumerable: false,
            writable: true
        },

        navOverlay: {
            value: function(event) {
                var $element = this.pagetools.content._element,
                    stateClass = "has-overlay disable-scroll",
                    overlayElement = "<div class=\"" + stateClass + " ie8-content-overlay\"/>",
                    _ieFallback = function(event) {
                        var ie8Overlay = $element.find(".ie8-content-overlay");
                        if (!!ie8Overlay.length) {
                            $element.find(".ie8-content-overlay")[event](stateClass);
                        } else {
                            $element.append(overlayElement);
                            $element.find(".ie8-content-overlay")[event](stateClass);
                        }
                    };

                switch(event) {
                    case "toggle":
                        if (this.isBrowser("ie8")) {
                            _ieFallback("toggleClass");
                        } else {
                            $element.toggleClass(stateClass);
                        }
                        break;
                    case "add":
                        if (this.isBrowser("ie8")) {
                            _ieFallback("addClass");
                        } else {
                            $element.addClass(stateClass);
                        }
                        break;
                    case "remove":
                        if (this.isBrowser("ie8")) {
                            _ieFallback("removeClass");
                        } else {
                            $element.removeClass(stateClass);
                        }
                        break;
                    default:
                        break;
                }
            },

            enumerable: false,
            writable: true
        },

        windowEvent: {
            value: function(state, eventNamespace, callback, element) {
                var $__arguments = arguments;
                var $element = element || view.$;
                switch(state) {
                    case "add":
                        $(this._window.document).on(eventNamespace, function(e) {
                            if ($element.find(e.target)[0] !== e.target) {
                                if ($element[0] !== e.target) {
                                    e.preventDefault();
                                    callback.call(this, $__arguments, e.target);
                                }
                            }
                        }.bind(this));
                        break;
                    case "remove":
                        $(this._window.document).unbind(eventNamespace);
                        break;
                    default:
                        break;
                }
            },

            enumerable: false,
            writable: true
        },

        isBrowser: {
            value: function(browser) {
                return this.$html.hasClass(browser);
            },

            enumerable: false,
            writable: true
        },

        closeNav: {
            value: function() {
                this.navOverlay("remove");
                view.$.find("> ul.level-1 > li").removeClass("browse");
                view.$.find("> ul.level-1 > li .level-2").hide();
            },

            enumerable: false,
            writable: true
        }
    });

    return ComPrimaryNavigation;
}(Menu);

return ComPrimaryNavigation;
});
}).apply(window);/**!!<[ModulePrimaryNavigation_com]!!**/
/**!![ModuleNearYou_com]>!!**/
(function(){
registerModule("ModuleNearYou", "com", function() {
;
function MazdaNearYou(){
    this.win = null;
    this.body = null;
    this.en = null;
    this.desktop = null;
    this.currentView = null;
    this.cookiesSet = false;
    this.country = null;
    this.continent = null;
    this.code = "GB";
    this.mdlClosed = true;
    setTimeout(function() {
        this.init.call(this, Services("pagetools"));
    }.bind(this));
}

MazdaNearYou.prototype = {

    construct: MazdaNearYou,

    init: function(pagetools){
        var self = this;
        this.win = pagetools.window._element;
        this.body = pagetools.body._element;
        this.html = $(this.win[0].document).find("html");
        this.languageCheck();
        this.geoApi();
        this.checkDimension();
        this.win.resize(function(event){
            self.checkDimension();
        });
    },

    languageCheck: function(){
        this.en = (this.body.hasClass("en")) ? true : false;
    },

    geoApi: function(){
        var CookieService = Services("cookies");
        if(CookieService.isCookieSet("CountryCode")){
            this.code =  CookieService.getCookie("CountryCode");
        }
        else{
            //this.code = "GB";
            this.getLocation();
        }
    },

    getLocation: function() {
        var self = this;
        $.ajax({
            url: "/api/geo/get",
            method: "GET",
            dataType: "json"
        }).done(function(data) {
            self.geo = data;
            self.setGeoCookies();
            self.code = self.geo.country.Code;
            console.log("=LANDING NOTIFICATION= request success");
        }).fail(function() {
            console.log("=LANDING NOTIFICATION= request failed");
            self.code = "GB";
        });
    },

    setGeoCookies: function() {
        var self= this;
        Services("cookies").setCookie(
            "CountryCode",
            self.geo.country.Code,
            1444897775432,
            "/"
        );
    },

    checkDimension: function(){
        this.desktop = (this.win.width() < 965) ? false : true;

        if(this.currentView != this.desktop){
            this.currentView = this.desktop;

            this.resetEvents();

            if(this.desktop){
                this.resetDesktop();
                this.bindDesktopEvents();
            }
            else{
                this.resetMobile();
                this.bindMobileEvents();
            }
        }
    },

    bindMobileEvents: function(){
        var self = this;

        $(".near-you-toggle").off().on("click", function(){
            self.toggleFirstLevel();
        });

        $(".current-position .mny-close").off().on("click", function(){
            self.toggleFirstLevel();
        });

        $(".change-location").off().on("click", function(){
            self.toggleFirstLevel();
            self.toggleSecondLvlTop();

            self.preselect(country, self.continent);
        });

        $("ul.tabs li").off().on("click", function(){
            self.selectContinent($(this));
            self.toggleSecondLvlTop();
            self.toggleSecondLvlBottom();
        });

        $(".single-continent .column li").off().on("click", function(){
            self.selectCountry($(this));
        });

        $(".second-lvl-top .mny-button-back").off().on("click", function(){
            self.toggleSecondLvlTop();
            self.toggleFirstLevel();
        });

        $(".second-lvl-top .mny-close").off().on("click", function(){
            self.toggleSecondLvlTop();
        });

        $(".second-lvl-bottom .mny-button-back").off().on("click", function(){
            self.toggleSecondLvlBottom();
            self.toggleSecondLvlTop();
        });

        $(".second-lvl-bottom .mny-close").off().on("click", function(){
            self.toggleSecondLvlBottom();
        });
    },

    checkCountryListPos: function(){
        var $countryList = view.$.find(".second-lvl"),
            countryListPos = $countryList.offset().top;
        if(countryListPos + $countryList.outerHeight() > $(this.win[0]).innerHeight()) {
            this.scrollToList(countryListPos);
        }
    },

    scrollToList: function(pos) {
        $(this.html[0]).animate({
          scrollTop: pos
        }, 500);

        $(this.body[0]).animate({
          scrollTop: pos
        }, 500);
    },

    bindDesktopEvents: function(){
        var self = this;

        //if clicked outside of module close mazda-near-you
        this.body.on("click", function(e){
            if(!self.mdlClosed){
                if( $(e.target).closest(".module-near-you").length > 0 ) {
                    return false;
                }else{
                    self.mdlClosed = true;
                    self.toggleFirstLevel();
                    return false;
                }
            }
        });



        $(".near-you-toggle").off().on("click", function(){
            self.toggleFirstLevel();
            self.mdlClosed = !self.mdlClosed;
        });

        $(".change-location").off().on("click", function(){
            self.toggleSecondLevel();
            //ie 8 fix
            self.bindDesktopEvents();

            setTimeout(function(){
                self.checkCountryListPos();
            },1000);
        });

        $("ul.tabs li").off().on("click", function(){
            self.selectContinent($(this));
        });

        $(".single-continent .column li").off().on("click", function(){
            var $countryList = view.$.find(".second-lvl"),
            countryListPos = $countryList.offset().top;

            if(countryListPos + $countryList.outerHeight() > $("self.win[0]").innerHeight()) {
                self.scrollToList(0);
            }

            self.selectCountry($(this));
        });
    },

    toggleSecondLvlTop: function(){
        view.$.find(".second-lvl-top").toggle();
    },

    toggleSecondLvlBottom: function(){
        view.$.find(".second-lvl-bottom").toggle("slide");
    },

    selectContinent: function(tab){
        var continent = tab.attr("data-tab");
        $("ul.tabs li.selected").removeClass("selected");
        tab.addClass("selected");
        $(".continents .single-continent").removeClass("show");
        $(".continents").find("[data-continent='"+tab.attr("data-tab")+"']").addClass("show");
    },

    selectCountry: function(countryEl){
        var self = this;
        $(".single-continent .column li").removeClass("selected");
        countryEl.addClass("selected");
        var continent = countryEl.closest(".single-continent").attr("data-continent");
        this.country = countryEl.attr("data-c-name");
        this.continent = continent;



        var updateSpeed;

        if(this.desktop){
            this.toggleSecondLevel();
            updateSpeed = 900;
        }
        else{
            this.toggleSecondLvlBottom();
            this.toggleFirstLevel();
            updateSpeed = 0;
        }

        setTimeout(function(){
            self.updateContactDetails(countryEl.attr("data-c-name"), continent , 0);
            $(".distr-link").on("click", function(e){
                this.win[0].open($(e.target).attr("href"), "_blank");
            }.bind(this));
        }.bind(this), updateSpeed);

        this.setCookies(countryEl.attr("data-c-name"), continent);
    },

    toggleFirstLevel: function(){
        this.getPreselectionSettings();
        if(this.desktop)
            view.$.find(".first-lvl").slideToggle(250);
        else
            view.$.find(".first-lvl").toggle();

        view.$.find(".first-lvl").toggleClass("isShown");
        if(view.$.find(".second-lvl").hasClass("isShown")){
            this.toggleSecondLevel();
        }
    },

    toggleSecondLevel: function(){
        this.preselect(this.country, this.continent);
        view.$.find(".second-lvl").slideToggle(250);
        view.$.find(".second-lvl").toggleClass("isShown");
    },

    getPreselectionSettings: function(){
        this.isCookieSet();

        if(this.cookiesSet){
            this.updateContactDetails(this.country, this.continent, 1);
        }
        else{
            var el = $(".continents").find("[data-c-code='"+this.code+"']");
            var country = el.attr("data-c-name");
            var continent = el.closest(".single-continent").attr("data-continent").toLowerCase();
            this.continent= continent;
            this.country = country;
            this.updateContactDetails(this.country, this.continent, 2);
        }
        $(".distr-link").on("click", function(e){
            this.win[0].open($(e.target).attr("href"), "_blank");
        }.bind(this));
    },

    updateContactDetails: function(country, continent, message) {
        var contact = $(".current-position"),
            distrField = $(".distr-address");

        //update html and set data attributes
        if (message === 0) {
            contact.find(".intro").html("");
        } else if (message === 2) {
            var weThink = (this.en) ? "We think you are in" : "お客様の現在地:";
            contact.find(".intro").html(weThink);
        } else {
            var lastTime = view.$.attr("data-lasttime");
            contact.find(".intro").html(lastTime);
        }

        contact.find(".country").html(country);
        contact.attr("data-c-name", country);
        contact.attr("data-continent", continent);
        //update address

        var address = $(".second-lvl .continents").find("[data-continent='" + continent + "']").find("[data-c-name=\"" + country + "\"]").find(".reference").html();

        distrField.removeClass("single multiple");

        if ((address.split("single-distr").length - 1) <= 1) {
            distrField.addClass("single");
        } else {
            distrField.addClass("multiple");
        }

        distrField.empty().html(address);
    },


    preselect: function(country, continent){
        $(".second-lvl ul.tabs li").removeClass("selected");
        $(".second-lvl .continents li").removeClass("show");
        $(".second-lvl ul.tabs").find("[data-tab='"+continent+"']").addClass("selected");
        $(".second-lvl .continents").find("[data-continent='"+continent+"']").addClass("show").find("[data-c-name=\"" + country + "\"]").addClass("selected");
    },

    isCookieSet: function(){
        var cookieConfig = {
            name: "MazdaNearYou"
        };
        var CookieService = Services("cookies");
        if(!CookieService.isCookieSet(cookieConfig.name)){
            this.cookiesSet = false;
        }
        else{
            this.cookiesSet = true;
            this.country =  CookieService.getCookie("MazdaNearYou-country");
            this.continent = CookieService.getCookie("MazdaNearYou-continent");
        }
    },

    setCookies: function(country, continent){
        var cookieConfig = {
            name: "MazdaNearYou",
            value: "true",
            expiry: 1444897775432, // 1 year (1000 * 3600 * 24 * 365)
            domain: "/"
        };

        var CookieService = Services("cookies");

        CookieService.setCookie(
                cookieConfig.name,
                cookieConfig.value,
                cookieConfig.expiry,
                cookieConfig.domain
        );

        CookieService.setCookie(
                "MazdaNearYou-country",
                country,
                cookieConfig.expiry,
                cookieConfig.domain
        );

        CookieService.setCookie(
                "MazdaNearYou-continent",
                continent,
                cookieConfig.expiry,
                cookieConfig.domain
        );
    },


    /* RESET FUNCTIONS */

    resetMobile: function(){
        $(".first-lvl ").removeClass("isShown");
        $(".first-lvl ").css({display: "none"});
        $(".second-lvl").css({display: "block"});
        $(".second-lvl").removeClass("isShown");
        $(".second-lvl-top").css({display: "none"});
        $(".second-lvl-bottom").css({display: "none"});
    },

    resetDesktop: function(){
        $(".first-lvl ").removeClass("isShown");
        $(".first-lvl ").css({display: "none"});
        $(".second-lvl").css({display: "none"});
        $(".second-lvl").removeClass("isShown");
        $(".second-lvl-top").css({display: "block"});
        $(".second-lvl-bottom").css({display: "block"});
    },

    resetEvents: function(){
        $(".near-you-toggle").off();
        $(".change-location").off();
        $("ul.tabs li").off();
        $(".single-continent .column li").off();
    }


};

return MazdaNearYou;
});
}).apply(window);/**!!<[ModuleNearYou_com]!!**/
/**!![ModuleSitemap_com]>!!**/
(function(){
registerModule("ModuleSitemap", "com", function() {
;
});
}).apply(window);/**!!<[ModuleSitemap_com]!!**/
/**!![ModuleLanguageSelector_com]>!!**/
(function(){
registerModule("ModuleLanguageSelector", "com", function() {
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */

var $__Object$defineProperties = Object.defineProperties;

var LanguageSelector = function() {
    "use strict";

    function LanguageSelector() {
        setTimeout(function() {
            this.pagetools = Services("pagetools");
            this.init();
        }.bind(this));
    }

    $__Object$defineProperties(LanguageSelector.prototype, {
        init: {
            value: function() {
                this.$body = this.pagetools.body._element;
                this.$body.find(".module-language-selector").on("touchstart click", "a", function(e) {
                    e.stopPropagation();
                });
            },

            enumerable: false,
            writable: true
        }
    });

    return LanguageSelector;
}();

return LanguageSelector;
});
}).apply(window);/**!!<[ModuleLanguageSelector_com]!!**/
/**!![ModuleSubNavigationPrimary_com]>!!**/
(function(){
registerModule("ModuleSubNavigationPrimary", "com", function() {
function SubNavModule(){
    var self = this;
    this.isMobileNavSet = false;
    this.win = null;
    this.desktop = null;
    this.body = null;
    this.subnavs = null;


    setTimeout(function() {
        this.init.call(this, Services("pagetools"));
    }.bind(this));
}


SubNavModule.prototype = {

    construct: SubNavModule,

    init: function(pagetools){
        var self = this;
        this.win = pagetools.window._element;
        this.body = pagetools.body._element;
        this.subnavs = this.body.find(".primary").length;
        this.appendMobileNav();
        this.win.on("resize", function(event){
            self.appendMobileNav();
        });
    },

    checkDimension: function(){
        this.desktop = (this.win.width() < 750) ? false : true;
    },

    appendMobileNav: function(){
        this.checkDimension();
        if(!this.desktop && !this.isMobileNavSet && this.body.find(".top-sub-nav.drop-down").length < this.subnavs){
            this.desktopReady = false;
            var primary = view.$.find(".primary").html();
            var wrapper = $("<nav class=\"top-sub-nav drop-down\">"+primary+"</nav>");
            var pageTitle = this.body.find("h1.page-title");
            pageTitle.addClass("is-nav");
            wrapper.insertAfter(pageTitle);
            this.ifTitleIsLink(wrapper);
            this.bindEvents();
        }
        else if(this.desktop && !this.desktopReady){
            this.desktopReady = true;
            var pageTitle = this.body.find("h1.page-title");
            this.body.find(".top-sub-nav.drop-down").remove();
            pageTitle.removeClass("is-nav");
        }
    },

    ifTitleIsLink: function(wrapper){
        var heading = wrapper.find("h2");
        var link;
        var title;
        var listElement;
        if(heading.find("a").length){
            link = heading.find("a");
            title = link.html();
            link.wrap("<li></li>");
            listElement = heading.find("li");
            wrapper.find("ul").prepend(listElement);
            heading.append(title);
        }
    },

    bindEvents: function(){
        var self = this;
        this.body.find(".top-sub-nav.drop-down").off().on("click", function(){
            self.toggleSubNav($(this));
        });
    },

    toggleSubNav: function(el){
        var topNavUl = el.find("ul");
        topNavUl.toggleClass("hiddenlist");
        el.toggleClass("opened");
    }       

};


return SubNavModule;
});
}).apply(window);/**!!<[ModuleSubNavigationPrimary_com]!!**/
/**!![ModuleSubNavigationSecondary_com]>!!**/
(function(){
registerModule("ModuleSubNavigationSecondary", "com", function() {
/*
    'use strict';

    function SubNavModule(){      
        this.init();        
    }

    SubNavModule.prototype = {

        construct: SubNavModule,

        init: function(){
            this.bindEvents();
        },

        bindEvents: function(){           
            var self = this;
            $('.sub-nav-heading').on('click', self.toggleSubNav.bind(this));
        },

        toggleSubNav: function(eventObject){ 
            console.log('anim');           
            var target = eventObject.delegateTarget;
            var topNavUl = $(target).parent().find('ul');
            topNavUl.slideToggle(); 
            $(target).find('span').toggleClass('rotated');           
        }     	

    };


return SubNavModule;









*/







;
});
}).apply(window);/**!!<[ModuleSubNavigationSecondary_com]!!**/
/**!![ModuleFooterNavigation_com]>!!**/
(function(){
registerModule("ModuleFooterNavigation", "com", function() {
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */;
});
}).apply(window);/**!!<[ModuleFooterNavigation_com]!!**/
/**!![ModuleFooterSubNavigation_com]>!!**/
(function(){
registerModule("ModuleFooterSubNavigation", "com", function() {
/**
 * @constructor
 */
var $__Object$defineProperties = Object.defineProperties;

var FooterSubNavigationModule = function() {
    "use strict";

    function FooterSubNavigationModule() {
        setTimeout(function() {
            this.pagetools = Services("pagetools");
            this.init();
        }.bind(this));
    }

    $__Object$defineProperties(FooterSubNavigationModule.prototype, {
        init: {
            value: function() {
                this.$window = this.pagetools.window._element;

                view.$.find("a[data-role=menu-trigger]").on("click", function(e) {
                    if (!this.isMobile()) {
                        events.click_navigationControl.desktop(e);
                    } else {
                        events.click_navigationControl.mobile(e);
                    }
                }.bind(this));

                var events = {
                    click_navigationControl: {
                        desktop: function(e) {},
                        mobile: function(e) {
                            e.preventDefault();
                            $(e.currentTarget).toggleClass("mobile-opened");
                        }
                    }
                };
            },

            enumerable: false,
            writable: true
        },

        isMobile: {
            value: function() {
                var width = this.$window[0].innerWidth || this.$window[0].document.documentElement.clientWidth || this.$window[0].document.body.clientWidth;
                return width < 768;
            },

            enumerable: false,
            writable: true
        }
    });

    return FooterSubNavigationModule;
}();

return FooterSubNavigationModule;
});
}).apply(window);/**!!<[ModuleFooterSubNavigation_com]!!**/
/**!![core_com]>!!**/
(function(){
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */;
}).apply(window);/**!!<[core_com]!!**/
/**!![ModulePromos_com]>!!**/
(function(){
registerModule("ModulePromos", "com", function() {
/**
 * @constructor
 */
function promos () {
  var config = {
      scope: view.$
  };
  setTimeout(function() {
    initEvents.call(this, Services("pagetools"), config);
  }.bind(this));
}

/**
 * @private
 */
var ieFilter = "",
    ieImage = "",
    $window = "";
function debounce(func, wait, immediate) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(function() {
      timeout = null;
      if (!immediate) func.apply(context, args);
    }, wait);
    if (immediate && !timeout) func.apply(context, args);
  };
}

function initEvents(pagetools, config) {
  $window = pagetools.window._element[0];



  new (Helpers("gallery-overlay"))(config);

  // Functions for img left and img right promos

  if (view.$.hasClass("img-right") || view.$.hasClass("img-left")){
    // Check Overflow Function

    var overflow = function(element){
      if (element.prop("clientHeight") < element.prop("scrollHeight")) {
        return true;
      } else {
        return false;
      }
    };

    // Add ellipsis markup

    $(".content", view.$).append("<span class=\"more-text\">...</span>");

    var $promoImage = $(".image img", view.$);
    var clampLines = debounce(function() {
      // The total height of the promo        
      var $target = $(".description", view.$),
          contentTop = Math.floor(parseInt($(".content",view.$).css("padding-top").replace("px",""))), // The padding at the top of the content box
          titleH = $(".title", view.$).outerHeight(true), // The title height
          catLinkH = $(".secondary-link", view.$).outerHeight(true), // The category link height
          ctaLinkH = view.$.hasClass("wrap-link") ? 0 : $(".promos-link", view.$).outerHeight(true), // The promo link height. If wrapped around promo, takes height of 0
          promoH = view.$.height();
      var copyLineH = ($(".description p", view.$).length) ? parseInt($(".description p", view.$).css("line-height").replace("px","")) : 0;
      // Divides the height by the number of lines and rounds down to ensure half lines are cut off, then multiplies it by the line-height again to give the final height of the box.
      // Set the target height as per calculations
      var availableH = promoH - (catLinkH + ctaLinkH + titleH + contentTop), // Calculates the available height for the descriptive text 
          adjustH = (Math.floor(availableH/copyLineH) * copyLineH);
      $target.height(adjustH);

      if (overflow($target)){
        // If the target overflows, check if any of it is visible
        // Only display elipsis if at least one line of text is visible
        if ($target.height() > 0){
          $(".content", view.$).addClass("ellipsis");
        }
      } else {
        $(".content", view.$).removeClass("ellipsis");
        $target.css("height", "");
      }
    }, 10);

    var image = new Image();

    image.onload = function () {
      clampLines();
    }
    image.onerror = function () {}

    image.src = $promoImage.attr("src");

    pagetools.window.on("resize", function(event){
      clampLines();
    });
  }


  // Image Top functions

  if (view.$.hasClass("img-top") && !view.$.hasClass("wrap-link")) {
    var setDescriptionProperties = debounce(function() {
      var $target = $(".description", view.$),
          ctaLinkH = $(".promos-link", view.$).outerHeight(true), // The promo link height
          contentPadding = Math.floor(parseInt($(".content",view.$).css("padding-bottom").replace("px","")));


      // Adjust margin bottom to account for height of ctaLink
      if (ctaLinkH > 0){
        ctaLinkH = ctaLinkH - contentPadding;
        $target.css("margin-bottom", ctaLinkH);
      }
    }, 10);

    setDescriptionProperties();

    pagetools.window.on("resize", function(event){
      setDescriptionProperties();
    });
  }

  if(view.$.hasClass("hero-full-width")){
    $("<div class=\"container container-zoomzoom\"><div class=\"zoomzoom\"></div></div>").insertBefore(".content", view.$);

    if(view.$.find(".title").text().length > 0){
      //only show title bar it there is title text
      view.$.addClass("show-title");
    }
  }

  if(view.$.hasClass("hero-full-width") && view.$.hasClass("wrap-link")){
    var $wrapperCell = view.$.find(".wrapper-cell");
    view.$.find("a.promos-link").clone().addClass("full-size-link").appendTo($wrapperCell);
  }
}


return promos;
});
}).apply(window);/**!!<[ModulePromos_com]!!**/
/**!![ModuleCookiesNotification_com]>!!**/
(function(){
registerModule("ModuleCookiesNotification", "com", function() {
/*
 * @module CookiesNotification
 */

/**
 * @name moduleConfig
 * @description Configuration object for CookiesNotification
 * @type {object}
 */
var $__Object$defineProperties = Object.defineProperties;
var moduleConfig = {
        cookieConfig: {
            name: "mazdaCookieNotifier",
            value: "accepted",
            expiry: 1444897775432, // 1 year (1000 * 3600 * 24 * 365)
            domain: "/"
        },
        closeButton: ".close-notification"
    };

var CookiesNotification = function() {
    "use strict";

    function CookiesNotification() {
        this.$body = null;

        setTimeout(function() {
            this.init.call(this, Services("pagetools"));
        }.bind(this));
    }

    $__Object$defineProperties(CookiesNotification.prototype, {
        init: {
            value: function(pagetools) {
                this.$body = pagetools.body._element;
                var notificationWrapper = this.$body.find(".notification");

                var CookieService = Services("cookies");
                // if cookies not set box is visible
                if (!CookieService.isCookieSet(moduleConfig.cookieConfig.name)) {
                    view.$.css("display", "block");
                    if(notificationWrapper.hasClass("cookies-null")){
                        notificationWrapper.removeClass("cookies-null").addClass("cookies-true");
                    }

                    var $closeButton = view.$.find(moduleConfig.closeButton);
                    $closeButton.on("click", function(event) {
                        event.preventDefault();
                        CookieService.setCookie(
                            moduleConfig.cookieConfig.name,
                            moduleConfig.cookieConfig.value,
                            moduleConfig.cookieConfig.expiry,
                            moduleConfig.cookieConfig.domain
                        );
                        view.$.css("display", "none");
                        if(notificationWrapper.hasClass("cookies-true")){
                            notificationWrapper.removeClass("cookies-true").addClass("cookies-false");
                        }
                    });
                }
                // if cookies set
                else{
                    if(notificationWrapper.hasClass("cookies-null")){
                        notificationWrapper.removeClass("cookies-null").addClass("cookies-false");
                    }
                }
            },

            enumerable: false,
            writable: true
        }
    });

    return CookiesNotification;
}();

return CookiesNotification;
});
}).apply(window);/**!!<[ModuleCookiesNotification_com]!!**/
/**!![ModuleLandingNotification_com]>!!**/
(function(){
registerModule("ModuleLandingNotification", "com", function() {
/*
 * @module LandingNotification
 */

/**
 * @name moduleConfig
 * @description Configuration object for LandingNotification
 * @type {object}
 */
var $__Object$defineProperties = Object.defineProperties;
var moduleConfig = {
        cookieConfig: {
            name: "mazdaCookieLanding",
            value: "accepted",
            expiry: 1444897775432, // 1 year (1000 * 3600 * 24 * 365)
            domain: "/"
        },
        closeButton: ".close-notification"
    };

var LandingNotification = function() {
    "use strict";

    function LandingNotification() {
        this.body = null;
        setTimeout(function() {
            this.init.call(this, Services("pagetools"));
        }.bind(this));
    }

    $__Object$defineProperties(LandingNotification.prototype, {
        init: {
            value: function(pagetools) {
                var self = this;
                self.body = pagetools.body._element;
                this.geoApi();
                var CookieService = Services("cookies");
                var notification = this.body.find(".notification");

                if (!CookieService.isCookieSet(moduleConfig.cookieConfig.name)) {
                    this.setClass();
                    view.$.css("display", "block");
                    this.bindEvent();
                    var $closeButton = view.$.find(moduleConfig.closeButton);
                    $closeButton.on("click", function(event) {
                        event.preventDefault();
                        CookieService.setCookie(
                            moduleConfig.cookieConfig.name,
                            moduleConfig.cookieConfig.value,
                            moduleConfig.cookieConfig.expiry,
                            moduleConfig.cookieConfig.domain
                        );
                        view.$.css("display", "none");
                        if(notification.hasClass("landing-true")){
                            notification.removeClass("landing-true").addClass("landing-false");
                        }
                    }.bind(this));
                }
                //if cookies are set
                else{
                    view.$.css("display", "none");
                    if(notification.hasClass("landing-null")){
                        notification.removeClass("landing-null").addClass("landing-false");
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        geoDetails: {
            value: function() {
                var paragraph = $(".content-block-2 .description").find("p");

                if ($("body").hasClass("en")) {
                    // replacing country name and distributor name
                    var countryRegex = paragraph.next().html().replace(/(\[){2}(country){1,}(\]){2}/g, this.geo.country.Name);
                    paragraph.next().html(countryRegex);
                    var distributorRegex = paragraph.next().html().replace(/(\[){2}(distributor){1,}(\]){2}/g, this.geo.dist.Name);
                    paragraph.next().html(distributorRegex);
                } else {
                    var countryRegex = paragraph.last().html().replace(/(\[){2}(country){1,}(\]){2}/g, this.geo.country.Name);
                    paragraph.last().html(countryRegex);
                    var distributorRegex = paragraph.last().html().replace(/(\[){2}(distributor){1,}(\]){2}/g, this.geo.dist.Name);
                    paragraph.last().html(distributorRegex);
                }

                //replacing distributor www          
                if (this.geo.dist.Url !== null) {
                    $(".content-block-2 .notification-link").first().attr("href", this.geo.dist.Url);
                } else {
                    $(".content-block-2 .notification-link").first().css({
                        display: "none"
                    });
                }
            },

            enumerable: false,
            writable: true
        },

        geoApi: {
            value: function() {
                var self = this;

                $.ajax({
                    url: "/api/geo/get",
                    method: "GET",
                    dataType: "json"
                }).done(function(data) {
                    self.geo = data;
                    self.setGeoCookies();
                    self.geoDetails();
                    console.log("=LANDING NOTIFICATION= request success");
                }).fail(function() {
                    console.log("=LANDING NOTIFICATION= request failed");
                });
            },

            enumerable: false,
            writable: true
        },

        setGeoCookies: {
            value: function() {
                var self= this;
                Services("cookies").setCookie(
                    "CountryCode",
                    self.geo.country.Code,
                    1444897775432, 
                    "/"
                );
            },

            enumerable: false,
            writable: true
        },

        setClass: {
            value: function() {
                var notification = this.body.find(".notification");

                if(notification.hasClass("landing-null")){
                    notification.removeClass("landing-null").addClass("landing-true");
                }
            },

            enumerable: false,
            writable: true
        },

        bindEvent: {
            value: function() {
                var self = this;
                view.$.find(".near-you").on("click", function(e) {
                    var CookieService = Services("cookies");
                    if(self.body.hasClass("en")){
                        CookieService.setCookie(
                            "mazdaCookieNotifier",
                            "accepted",
                            1444897775432,
                            "/"
                        );
                    }
                    CookieService.setCookie(
                        "mazdaCookieLanding",
                        "accepted",
                        1444897775432, 
                        "/"
                    );
                    self.body.find(".module-cookies-notification").hide("slow");
                    view.$.hide("slow", function(){
                        self.body.find(".notification").removeClass("cookies-true").addClass("cookies-false");
                        self.body.find(".notification").removeClass("landing-true").addClass("landing-false");
                        self.body.find(".module-near-you .near-you-toggle").click();
                    });
                });

                /*        view.$.find('.near-you').on('click', function(e) {         
                            e.preventDefault();           
                            if(self.body.find('.notification').hasClass('cookies-true')){               
                                //it means that cookie notification is visible, tell to accept first                
                                view.$.find('.content-block-2').find('.cookieMessage').css({display: "block"});
                                self.bindReadMore();
                            }

                            else{              
                                self.body.find('.module-landing-notification').css({display: 'none'});
                                self.body.find('.notification').removeClass('landing-true').addClass('landing-false');
                                view.$.find('.cookieMessage').css({display: "none"});
                                self.body.find('.module-near-you .near-you-toggle').click();
                                var CookieService = Services('cookies');
                                CookieService.setCookie(
                                    moduleConfig.cookieConfig.name,
                                    moduleConfig.cookieConfig.value,
                                    moduleConfig.cookieConfig.expiry,
                                    moduleConfig.cookieConfig.domain
                                );  
                            } 
                        });*/;
            },

            enumerable: false,
            writable: true
        }
    });

    return LandingNotification;
}();

return LandingNotification;
});
}).apply(window);/**!!<[ModuleLandingNotification_com]!!**/
/**!![ModuleHeaderSearch_com]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_autosuggest"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "	    <li><a title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.word : depth0), depth0))
    + "\" href=\"#\">"
    + escapeExpression(lambda((depth0 != null ? depth0.word : depth0), depth0))
    + "</a></li>   \n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"autosuggest\">\n	<ul>\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "	</ul>\n</div>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('ModuleHeaderSearch.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerModule("ModuleHeaderSearch", "com", function() {
/*if (typeof window.ISearchAssist_digiana == "undefined") {
    onerror = function() {
        return true
    };
    (function() {
        var D, E = ["/common/js/sa/jsonp.js", "/common/js/sa/yahoo-min.js", "/common/js/sa/dom-min.js", "/common/js/sa/searchAssistTemplate.js?name=i_assist_tmpl", "/common/js/sa/iSearchAssistJSON.js"];
        var A = ["#suggest_frame {visibility:hidden; position:absolute; z-index:1000; border:0px; width:102px;}"];
        var C = ["body {border:0px; margin:0px; color:#333; padding:0px; overflow:hidden; font-size:85%; font-family:sans-serif}", "#suggest_area {background-color:#FFFFFF}", "#suggest_area .selected {background-color:#ECF5FA}", "#suggest_area table {border-collapse:collapse; border-left:1px solid #ccc; border-right:2px solid #999; border-bottom:2px solid #bbb}", "#suggest_area td {border-width:0px; line-height:1.3em; padding:3px}", ".suggest_row_0 td,.suggest_row_1 td  {border-top: solid #ccc 1px !important}", ".suggest_row_0 td {background-color:#FFFFFF}", ".suggest_row_1 td {background-color:#FFFFFF}", ".suggest_data_word {cursor:pointer}", ".suggest_data_graph {background-color:#FFFFFF}", ".suggest_data_graph div {background-color:#E0FFFF; border-bottom:1px solid #6699FF;border-left:1px solid #6699FF;}"];
        for (var D = 0; D < E.length; D++) {
            document.write('<script type="text/javascript" src="' + E[D] + '"></script>')
        }
        document.write('<style type="text/css"><!--' + A.join("") + "--></style>");
        var B = window.onload;
        onload = function() {
            var G = jQuery("#i_search_text_input,#i_search_text_input2,#i_search_text_input3,#i_search_text_input4");
            if (G) {
                var F = {
                    interface_url: "https://i24.dga.jp/mazda/i_search_assist.php",
                    input_jquery: G,
                    clone_styles: ["fontSize", "lineHeight", "fontFamily"],
                    array_styles: C,
                    show_data_graph: false
                };
                iSearchAssistJSON(F)
            }
            if (B) {
                B()
            }
        }
    })()
}
ISearchAssist_digiana = 1;

var jsonp = {
    load: function(F, D, E) {
        if (typeof F == "undefined") {
            F = "jsonp"
        }
        var B = document.getElementById(F);
        if (B) {
            var C = B.parentNode;
            C.removeChild(B);
            if (!D) {
                D = B.src
            }
        } else {
            C = document.body
        }
        var A = document.createElement("script");
        A.id = F;
        A.type = "text/javascript";
        if (E) {
            A.charset = E
        }
        A.src = D;
        C.appendChild(A)
    }
};

i_assist_tmpl = function(A, C) {
    if (A == undefined) {
        A = {}
    }
    try {
        var B = [];
        B.p = B.push;
        var F = A.prefix;
        var H = A.handler;
        var D = A.data;
        B.p('<table cellpadding="0" cellspacing="0" border="0" width="100%">\n');
        if (D && D.length) {
            for (var E = 0; E < D.length; E++) {
                B.p('<tr class="suggest_row_');
                B.p(E % 2);
                B.p('">\n<td align="left" id="');
                B.p(F);
                B.p(E);
                B.p('"\n\tclass="suggest_data_word"\n\tstyle="\n\t\tfont-size: 12px;\n\t\tpadding-left: 2px;\n\t"\n\tonmouseover="try{');
                B.p(H);
                B.p(".focus(");
                B.p(E);
                B.p(');}catch(e){}"\n\tonmousedown="try{');
                B.p(H);
                B.p('.suggest_mousedown(event);}catch(e){}"\n\tonclick="try{');
                B.p(H);
                B.p('.suggest_click(event);}catch(e){}"\n\tnowrap\n>');
                B.p(D[E].word);
                B.p('</td>\n<td align="left" valign="middle"\n\tclass="suggest_data_graph"\n\t><div\n\t\t style="\n\t\t\twidth: ');
                B.p(Math.floor(D[E].point * 2));
                B.p('px;\n\t\t\theight: 3px;\n\t\t\toverflow:hidden;\n\t\t "\n\t></div\n></td>\n</tr>\n')
            }
        }
        B.p("</table>\n")
    } catch (G) {
        return {
            exception: G,
            message: "An exception occurred while excuting template. Error type: " + G.name + ". Error message: " + G.message
        }
    }
    var I = B.join("");
    if (typeof C != "undefined") {
        if (typeof C == "string") {
            C = document.getElementById(C)
        }
        C.innerHTML = I
    }
    return I
};

function iSearchAssistJSON(a) {
    var f = "";
    var g = false;
    var b = null;
    var h = null;
    a.interface_url = a.interface_url || "https://i24.dga.jp/mazda/i_search_assist.php";
    a.handler_name = a.handler_name || "parent.suggest_ctxt";
    a.callback = a.callback || "load_kw_candidate";
    a.selected_bgcolor = a.selected_bgcolor || "#ECF5FA";
    a.max = a.max || 10;
    var c;
    var i = function() {
        if (c) {
            return
        }
        try {
            var j = document.getElementById("suggest_frame").contentWindow.document;
            if (!a.show_data_graph) {
                a.array_styles = a.array_styles || [];
                a.array_styles[a.array_styles.length] = ".suggest_data_graph {display:none}"
            }
            if (a.array_styles) {
                j.write('<style type="text/css"><!-- ' + a.array_styles.join("") + "--></style>")
            }
            j.write('<body><div id="suggest_area"></div></body>');
            j.close();
            j.body.scroll = "no";
            var x = j.getElementById("suggest_area");
            x.onselectstart = x.oncontextmenu = function() {
                return false
            };
            if (a.clone_styles) {
                for (var H = 0; H < a.clone_styles.length; H++) {
                    h.css(a.clone_styles[H], a.input_jquery.css(a.clone_styles[H]))
                }
            }
            var G = "suggest_data_";
            var w = a.handler_name;
            var k = w.replace(/^[^.]*\.(.*)$/, "$1");
            if (!window[k]) {
                window[k] = {}
            }
            var F = function() {
                h.css("visibility", "visible")
            };
            var K = function() {
                h.css("visibility", "hidden")
            };
            var J = function(N, O) {
                if (!arguments.length) {
                    var P = j.getElementsByTagName("TABLE")[0];
                    N = P.offsetWidth;
                    O = P.offsetHeight;
                    if (e) {
                        N += 3;
                        O++
                    }
                }
                b.style.width = N + "px";
                b.style.height = O + "px"
            };
            window.resize_suggest = J;
            var L = function() {
                return h.css("visibility") == "visible"
            };
            var n = function(N) {
                return j.getElementById(N)
            };
            window[a.callback] = function(N) {
                if (!N || N.length == 0) {
                    return
                }
                var Q = jQuery("#" + f).get(0);
                var R = YAHOO.util.Dom.getXY(Q);
                if (location.href.match("http://sitesearch.mazda.jp/")) {
                    b.style.left = R[0] + "px";
                } else {
                    b.style.left = R[0] - jQuery("#header").offset().left - 1 + "px";
                }
                b.style.top = (R[1] + Q.offsetHeight) - 2 + "px";
                b.style.width = Q.offsetWidth + "px";
                var O = {
                    prefix: G,
                    handler: w,
                    data: N
                };
                i_assist_tmpl(O, x);
                setTimeout("resize_suggest()", 0);
                C = N;
                m = -1;
                g = false;
                try {
                    if (N[0].word.length > 0) {
                        g = true
                    }
                } catch (P) {}
                if (g) {
                    F()
                } else {
                    K()
                }
            };
            var l = function(N) {
                if (N.match(/^\s*$/)) {
                    return false
                }
                var P = ["callback=" + a.callback, "q=" + encodeURIComponent(N), "ie=utf8", "max=" + a.max];
                if (a.array_queries) {
                    P = P.concat(a.array_queries)
                }
                var O = a.interface_url + "?" + P.join("&");
                jsonp.load("jsonp_suggest", O, "UTF-8");
                return O
            };
            var u = a.input_jquery.val();
            var C = [];
            var m = -1;
            var A = function(N) {
                if (typeof N != "undefined") {
                    z();
                    m = N
                }
                if (C[m]) {
                    var O = n(G + m);
                    O.backgroundColorOrg = O.style.backgroundColor;
                    O.style.backgroundColor = a.selected_bgcolor
                }
            };
            window[k]["focus"] = A;
            var z = function() {
                if (C[m]) {
                    var N = n(G + m);
                    N.style.backgroundColor = N.backgroundColorOrg
                }
            };
            var s = function() {
                if (m < 0) {
                    m = 0
                } else {
                    z();
                    m++
                }
                if (m >= C.length) {
                    m = -1;
                    return
                }
                A()
            };
            var r = function() {
                if (m < 0) {
                    m = C.length - 1
                } else {
                    z();
                    m--;
                    if (m == -1) {
                        return
                    }
                }
                A()
            };
            var D = function() {
                var N = C[m];
                if (N) {
                    if (a.input_jquery.val() != N.word) {
                        a.input_jquery.val(N.word);
                        u = N.word;
                        l(N.word + " ");
                        return false
                    }
                }
                return true
            };
            var y;
            window[k]["suggest_mousedown"] = function(N) {
                y = (new Date()).getTime()
            };
            window[k]["suggest_click"] = function(N) {
                jQuery("#" + f).get(0).focus();
                if (D()) {
                    try {
                        jQuery("#" + f).parents("form").get(0).onsubmit()
                    } catch (N) {
                        jQuery("#" + f).get(0).form.submit()
                    }
                } else {
                    return false
                }
            };
            var q = {
                "9": "tab",
                "16": "shift",
                "17": "ctl",
                "27": "esc",
                "18": "alt",
                "19": "pause/break",
                "20": "caps lock",
                "33": "pageup",
                "34": "pagedown",
                "35": "end",
                "36": "home",
                "37": "left",
                "38": "up",
                "40": "down",
                "44": "print screen",
                "45": "ins"
            };
            var B = false;
            var p = function(N) {
                if (typeof N == "object") {
                    N = N.keyCode
                }
                if (N == 16) {
                    B = false
                }
                if (N == 13 && m != -1) {
                    return false
                }
                if (q[N]) {
                    return false
                }
            };
            var E = function() {
                var N = jQuery("#" + f).val();
                if (u == N) {
                    return
                }
                u = N;
                if (N == "") {
                    C = [];
                    K()
                } else {
                    l(N)
                }
            };
            var M;
            var o = function() {
                if (!M) {
                    M = setInterval(E, 100)
                }
            };
            var t = function() {
                if (!M) {
                    return
                }
                clearInterval(M);
                M = null
            };
            var v = {
                keyup: function(N) {
                    f = this.id;
                    (p(N) != false) && E()
                },
                keypress: function(N) {
                    f = this.id;
                    (p(N) != false) && o()
                },
                keydown: function(N) {
                    if (typeof N == "object") {
                        N = N.keyCode
                    }
                    if (N == 16) {
                        B = true
                    }
                    switch (N) {
                        case 9:
                            if (!L()) {
                                return true
                            }
                            if (B) {
                                r()
                            } else {
                                s()
                            }
                            break;
                        case 40:
                            s();
                            break;
                        case 38:
                            r();
                            break;
                        case 27:
                            K();
                            break;
                        case 13:
                            if (!D()) {
                                break
                            }
                        default:
                            return
                    }
                    return false
                },
                blur: function(O) {
                    var N = (new Date()).getTime();
                    if (y + 100 > N) {
                        return
                    }
                    t();
                    K()
                },
                focus: function(N) {
                    if (C.length == 0 || !g) {
                        return
                    }
                    F()
                }
            };
            if (window.opera || (navigator.userAgent.indexOf("Gecko") >= 0 && navigator.userAgent.indexOf("KHTML") == -1)) {
                a.input_jquery.keypress(v.keypress)
            } else {
                a.input_jquery.keyup(v.keyup)
            }
            a.input_jquery.keydown(v.keydown).blur(v.blur).focus(v.focus);
            if (d) {
                clearInterval(d)
            }
            c = true
        } catch (I) {}
    };
    var d;
    var e = navigator.userAgent.match(/AppleWebKit\/4\d\d/);
    a.input_jquery.attr("autocomplete", "off");
    var b = document.createElement("IFRAME");
    var h = jQuery(b);
    b.name = "suggest_frame";
    b.id = "suggest_frame";
    b.frameBorder = 0;
    b.scrolling = "no";
    h.css("position", "absolute").css("visibility", "hidden").css("zIndex", 1000).css("top", "0px").css("height", "0px").css("border", "0px");
    if (window.location.protocol == "https:" && window.navigator.userAgent.match("MSIE 6")) {
        b.src = "javascript:"
    } else {
        b.src = "about:blank"
    }
    document.body.appendChild(b);
    i();
    if (e) {
        d = setInterval(i, 100)
    }
};

function URLencode(str){
    var i, encoded_str, char_code, padded_str;
    encoded_str = "";
    for (i = 0; i < str.length; i++){
        char_code = str.charCodeAt(i);
        if (char_code == 0x20){
            encoded_str += "+";
        }
        else {
            if (((0x30 <= char_code) && (char_code <= 0x39)) || ((0x41 <= char_code) && (char_code <= 0x5a)) || ((0x61 <= char_code) && (char_code <= 0x7a))){
                encoded_str += str.charAt(i);
            }
            else if ((char_code == 0x2a) || (char_code == 0x2e) || (char_code == 0x2d) || (char_code == 0x5f)) {
                encoded_str += str.charAt(i);
            }
            else {
                if ( char_code > 0xffff ) {
                    encoded_str += "%" + ((char_code >> 18) | 0xf0).toString(16).toUpperCase();
                    encoded_str += "%" + (((char_code >> 12) & 0x3f) | 0x80).toString(16).toUpperCase();
                    encoded_str += "%" + (((char_code >> 6) & 0x3f) | 0x80).toString(16).toUpperCase();
                    encoded_str += "%" + ((char_code & 0x3f) | 0x80).toString(16).toUpperCase();
                }
                else if ( char_code > 0x7ff ) {
                    encoded_str += "%" + ((char_code >> 12) | 0xe0).toString(16).toUpperCase();
                    encoded_str += "%" + (((char_code >> 6) & 0x3f) | 0x80).toString(16).toUpperCase();
                    encoded_str += "%" + ((char_code & 0x3f) | 0x80).toString(16).toUpperCase();
                }
                else if ( char_code > 0x7f ) {
                    encoded_str += "%" + (((char_code >> 6) & 0x1f) | 0xc0).toString(16).toUpperCase();
                    encoded_str += "%" + ((char_code & 0x3f) | 0x80).toString(16).toUpperCase();
                }
                else {
                    padded_str = "0" + char_code.toString(16).toUpperCase();
                    encoded_str += "%" + padded_str.substr(padded_str.length - 2, 2);
                }
            }
        }
    }
    return encoded_str;
}

function mysearch(){
    url = 'http://sitesearch.mazda.jp/?ref='+URLencode(location.href)+'&kw='+URLencode(document.search_form.kw.value)+'&ie='+document.search_form.ie.value+'&by=js&type='+document.search_form.type.value;
    document.location.href=url;
    return false;
}
function new_mysearch(obj){
    url = 'http://sitesearch.mazda.jp/?ref='+URLencode(location.href)+'&kw='+URLencode(obj.kw.value)+'&ie='+obj.ie.value+'&by=js&type='+obj.type.value;
    document.location.href=url;
    return false;
}*/;
var $__Object$defineProperties = Object.defineProperties;

var SearchSubmit = function() {
    "use strict";

    function SearchSubmit($form) {
        this.pagetools = Services("pagetools");
        this.form = $form[0];
        this.init();
    }

    $__Object$defineProperties(SearchSubmit.prototype, {
        init: {
            value: function() {
                var url = this.form.action,
                    formElements = this.form.elements,
                    queryParameters = "?ref=" + this.urlEncode(this.form.baseURI) + "&kw=" + this.urlEncode(formElements.kw.value) + "&ie=" + formElements.ie.value + "&by=js&type=" + formElements.type.value + "&temp=" + formElements.type.value;

                url = url + queryParameters;
                if (!!url) {
                    this.pagetools.window._element[0].document.location.href = url;
                }
            },

            enumerable: false,
            writable: true
        },

        urlEncode: {
            value: function(str) {
                if (str) {
                    var i, encoded_str, char_code, padded_str;
                    encoded_str = "";
                    for (i = 0; i < str.length; i++){
                        char_code = str.charCodeAt(i);
                        if (char_code == 32){
                            encoded_str += "+";
                        }
                        else {
                            if (((48 <= char_code) && (char_code <= 57)) || ((65 <= char_code) && (char_code <= 90)) || ((97 <= char_code) && (char_code <= 122))){
                                encoded_str += str.charAt(i);
                            }
                            else if ((char_code == 42) || (char_code == 46) || (char_code == 45) || (char_code == 95)) {
                                encoded_str += str.charAt(i);
                            }
                            else {
                                if ( char_code > 65535 ) {
                                    encoded_str += "%" + ((char_code >> 18) | 240).toString(16).toUpperCase();
                                    encoded_str += "%" + (((char_code >> 12) & 63) | 128).toString(16).toUpperCase();
                                    encoded_str += "%" + (((char_code >> 6) & 63) | 128).toString(16).toUpperCase();
                                    encoded_str += "%" + ((char_code & 63) | 128).toString(16).toUpperCase();
                                }
                                else if ( char_code > 2047 ) {
                                    encoded_str += "%" + ((char_code >> 12) | 224).toString(16).toUpperCase();
                                    encoded_str += "%" + (((char_code >> 6) & 63) | 128).toString(16).toUpperCase();
                                    encoded_str += "%" + ((char_code & 63) | 128).toString(16).toUpperCase();
                                }
                                else if ( char_code > 127 ) {
                                    encoded_str += "%" + (((char_code >> 6) & 31) | 192).toString(16).toUpperCase();
                                    encoded_str += "%" + ((char_code & 63) | 128).toString(16).toUpperCase();
                                }
                                else {
                                    padded_str = "0" + char_code.toString(16).toUpperCase();
                                    encoded_str += "%" + padded_str.substr(padded_str.length - 2, 2);
                                }
                            }
                        }
                    }
                    return encoded_str;
                }
                return "";
            },

            enumerable: false,
            writable: true
        }
    });

    return SearchSubmit;
}();
/**
 * @class HeaderSearch
 * @classdesc Manages events on Header Search
 */

var $__Object$defineProperties = Object.defineProperties;

var HeaderSearch = function() {
    "use strict";

    function HeaderSearch() {
        this.Templates = {
           _autoSuggest: Services("templateService").templates("ModuleHeaderSearch._autosuggest")
       };

        this.config = {
            autoSuggest: {
                url: "https://i24.dga.jp/mazda/i_search_assist.php?ie=utf8",
                maxResults: 10
            }        };
        setTimeout(function() {
            this.pagetools = Services("pagetools");
            this.init();
        }.bind(this));
    }

    $__Object$defineProperties(HeaderSearch.prototype, {
        init: {
            value: function() {
                this.$window = this.pagetools.window._element;
                this._window = this.$window[0];
                this._document = this._window.document;
                this.$html = $(this._document).find("html");
                this.$body = this.pagetools.body._element;



                this.$form = $("form[name=\"search_form\"]");
                this.config.formAction = this.$form.attr("action");
                this.$searchInput = this.$form.find("#header-search");
                this.postProcessForm();
                this.bindSearchEvents();
                this.bindAutoSuggestEvents();

                if (this.isBrowser("ie8") || this.isBrowser("ie9")) {
                    this.setPlaceholder();
                }
            },

            enumerable: false,
            writable: true
        },

        postProcessForm: {
            value: function() {
                var $typeField = $(this.$form[0].elements.type),
                    typeValue = this.isMobile() ? $typeField.attr("data-mobile") : $typeField.attr("data-desktop");

                $typeField.attr("value", typeValue);
            },

            enumerable: false,
            writable: true
        },

        bindSearchEvents: {
            value: function() {
                view.$.on("click", function(event) {
                    // Reveal search for Desktop
                    event.preventDefault();
                    if (this.$searchInput[0] !== event.target && this.$form.find(event.target)[0] !== event.target) {
                        this.toggleHeaderSearch();
                    } else {
                        this.openHeaderSearch();
                    }
                }.bind(this)).on("click", ".button-clear", function(event) {
                    event.preventDefault();
                    this.removeAutoSuggest();
                    if (this.isBrowser("ie8") || this.isBrowser("ie9")) {
                        this.setPlaceholder();
                    } else {
                        this.$searchInput.val("");
                    }
                }.bind(this)).on("click", ".button-search", function(event) {
                    event.preventDefault();
                    if (SearchSubmit) {
                        new SearchSubmit(this.$form);
                    }
                }.bind(this));

                var inputAction = this.debounce(function(event) {
                    this.startAutoSuggest(event.currentTarget.value);
                }.bind(this), 200);

                this.$form.on("change paste keyup", ".header-search-input", function(event) {
                    inputAction(event);
                });
            },

            enumerable: false,
            writable: true
        },

        setPlaceholder: {
            value: function() {
                var language = this.getLanguage(),
                    placeholder = {
                        placeText: {
                            en: "Search",
                            ja: "検索"
                        },
                        _set: function() {
                            if (!!language && !this.$searchInput.attr("value") && this.$searchInput.attr("value") !== placeholder.placeText[language]) {
                                this.$searchInput.attr("value", placeholder.placeText[language]);
                            }
                        }.bind(this),
                        _remove: function() {
                            if (!!language && this.$searchInput.attr("value") === placeholder.placeText[language]){
                                this.$searchInput.attr("value", "");
                            }
                        }.bind(this)
                    };
                placeholder._set();
                this.$searchInput.focus(placeholder._remove).blur(placeholder._set);
            },

            enumerable: false,
            writable: true
        },

        toggleHeaderSearch: {
            value: function() {
                // Hide search for Desktop
                if (!this.isMobile()) {
                    if (view.$.hasClass("selected")) {
                        this.closeHeaderSearch();
                    } else {
                        this.openHeaderSearch();
                    }
                } else {
                    // Toggle search visibility for Mobile
                    if (view.$.hasClass("selected")) {
                        this.closeHeaderSearch();
                    } else {
                        this.openHeaderSearch();
                        this.closeMainNav();
                    }
                }
            },

            enumerable: false,
            writable: true
        },

        openHeaderSearch: {
            value: function() {
                if (!view.$.hasClass("selected")) {
                    view.$.addClass("selected");
                    this.addOverlay();
                    $(this._window.document).on("click.headerSearch", function(event) {
                        if (view.$.find(event.target)[0] !== event.target) {
                            if (view.$[0] !== event.target) {
                                this.closeHeaderSearch();
                            }
                        }
                    }.bind(this));
                }
            },

            enumerable: false,
            writable: true
        },

        closeHeaderSearch: {
            value: function() {
                view.$.removeClass("selected");
                this.removeOverlay();
                $(this._window.document).unbind("click.headerSearch");
            },

            enumerable: false,
            writable: true
        },

        closeMainNav: {
            value: function() {
                var $header = this.pagetools.header._element;
                if (this.$body.hasClass("open-main-nav")) {
                    this.$body.removeClass("open-main-nav");
                }
            },

            enumerable: false,
            writable: true
        },

        startAutoSuggest: {
            value: function(query) {
                var dataUrl = this.config.autoSuggest.url + "&q=" + query + "&max=" + this.config.autoSuggest.maxResults;
                if (!!query) {
                    this._window.load_kw_candidate = function(data) {
                        if (!!data.length) {
                            this.renderAutoSuggest(data);
                        }
                    }.bind(this);
                    $.getJSON(dataUrl + "&callback=?");
                } else {
                    this.removeAutoSuggest();
                }
            },

            enumerable: false,
            writable: true
        },

        renderAutoSuggest: {
            value: function(data) {
                var temp = {
                    items: data
                },
                    html = this.Templates._autoSuggest(temp),
                    $autoSuggest = this.$form.find(".autosuggest");

                if (!$autoSuggest.length) {
                    this.$form.append(html);
                } else {
                    $autoSuggest.replaceWith(html);
                }
            },

            enumerable: false,
            writable: true
        },

        bindAutoSuggestEvents: {
            value: function() {
                this.$form.on("click", ".autosuggest a", function(e) {
                    e.preventDefault();
                    var elementText = e.currentTarget.text || e.currentTarget.textContent || e.currentTarget.innerText;
                    this.setInputValue(elementText);
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        setInputValue: {
            value: function(value) {
                this.$searchInput.val(value);
            },

            enumerable: false,
            writable: true
        },

        removeAutoSuggest: {
            value: function() {
                this.$form.find(".autosuggest").remove();
            },

            enumerable: false,
            writable: true
        },

        debounce: {
            value: function(func, wait, immediate) {
                var timeout;
                return function() {
                    var context = this, args = arguments;
                    clearTimeout(timeout);
                    timeout = setTimeout(function() {
                        timeout = null;
                        if (!immediate) func.apply(context, args);
                    }, wait);
                    if (immediate && !timeout) func.apply(context, args);
                };
            },

            enumerable: false,
            writable: true
        },

        isMobile: {
            value: function() {
                var width = this.$window[0].innerWidth || this.$window[0].document.documentElement.clientWidth || this.$window[0].document.body.clientWidth;
                return width < 768;
            },

            enumerable: false,
            writable: true
        },

        isBrowser: {
            value: function(browser) {
                return this.$html.hasClass(browser);
            },

            enumerable: false,
            writable: true
        },

        addOverlay: {
            value: function() {
                view.$.addClass("has-overlay");
                view.$.addClass("disable-scroll");
                this.$body.addClass("disable-scroll");
            },

            enumerable: false,
            writable: true
        },

        removeOverlay: {
            value: function() {
                view.$.removeClass("has-overlay");
                view.$.removeClass("disable-scroll");
                this.$body.removeClass("disable-scroll");
            },

            enumerable: false,
            writable: true
        },

        getLanguage: {
            value: function() {
                return  this.$body.hasClass("ja") ? "ja" : "en";
            },

            enumerable: false,
            writable: true
        }
    });

    return HeaderSearch;
}();


return HeaderSearch;
});
}).apply(window);/**!!<[ModuleHeaderSearch_com]!!**/
/**!![ModuleFeed_com]>!!**/
(function(){
registerModule("ModuleFeed", "com", function() {
/*
 *	jQuery dotdotdot 1.6.16
 *
 *	Copyright (c) Fred Heusschen
 *	www.frebsite.nl
 *
 *	Plugin website:
 *	dotdotdot.frebsite.nl
 *
 *	Dual licensed under the MIT and GPL licenses.
 *	http://en.wikipedia.org/wiki/MIT_License
 *	http://en.wikipedia.org/wiki/GNU_General_Public_License
 */
!function(t,e){
 function n(t,e,n){
  var r=t.children(),o=!1;t.empty();for(var i=0,d=r.length;d>i;i++){
   var l=r.eq(i);if(t.append(l),n&&t.append(n),a(t,e)){
    l.remove(),o=!0;break;
   }n&&n.detach();
  }return o;
 }function r(e,n,i,d,l){
  var s=!1,c="table, thead, tbody, tfoot, tr, col, colgroup, object, embed, param, ol, ul, dl, blockquote, select, optgroup, option, textarea, script, style",u="script, .dotdotdot-keep";return (e.contents().detach().each(function(){
   var f=this,h=t(f);if("undefined"==typeof f||3==f.nodeType&&0==t.trim(f.data).length)return!0;if(h.is(u))e.append(h);else{
    if(s)return!0;e.append(h),l&&e[e.is(c)?"after":"append"](l),a(i,d)&&(s=3==f.nodeType?o(h,n,i,d,l):r(h,n,i,d,l),s||(h.detach(),s=!0)),s||l&&l.detach();
   }
  }), s);
 }function o(e,n,r,o,d){
  var c=e[0];if(!c)return!1;var f=s(c),h=-1!==f.indexOf(" ")?" ":"　",p="letter"==o.wrap?"":h,g=f.split(p),v=-1,w=-1,b=0,y=g.length-1;for(o.fallbackToLetter&&0==b&&0==y&&(p="",g=f.split(p),y=g.length-1);y>=b&&(0!=b||0!=y);){
   var m=Math.floor((b+y)/2);if(m==w)break;w=m,l(c,g.slice(0,w+1).join(p)+o.ellipsis),a(r,o)?(y=w,o.fallbackToLetter&&0==b&&0==y&&(p="",g=g[0].split(p),v=-1,w=-1,b=0,y=g.length-1)):(v=w,b=w);
  }if(-1==v||1==g.length&&0==g[0].length){
   var x=e.parent();e.detach();var T=d&&d.closest(x).length?d.length:0;x.contents().length>T?c=u(x.contents().eq(-1-T),n):(c=u(x,n,!0),T||x.detach()),c&&(f=i(s(c),o),l(c,f),T&&d&&t(c).parent().append(d));
  }else f=i(g.slice(0,v+1).join(p),o),l(c,f);return!0;
 }function a(t,e){
  return t.innerHeight()>e.maxHeight;
 }function i(e,n){
  for(;t.inArray(e.slice(-1),n.lastCharacter.remove)>-1;)e=e.slice(0,-1);return (t.inArray(e.slice(-1),n.lastCharacter.noEllipsis)<0&&(e+=n.ellipsis), e);
 }function d(t){
  return{width: t.innerWidth(),height: t.innerHeight()}
 }function l(t,e){
  t.innerText?t.innerText=e:t.nodeValue?t.nodeValue=e:t.textContent&&(t.textContent=e);
 }function s(t){
  return t.innerText?t.innerText:t.nodeValue?t.nodeValue:t.textContent?t.textContent:"";
 }function c(t){
  do t=t.previousSibling;while(t&&1!==t.nodeType&&3!==t.nodeType);return t;
 }function u(e,n,r){
  var o,a=e&&e[0];if(a){
   if(!r){
    if(3===a.nodeType)return a;if(t.trim(e.text()))return u(e.contents().last(),n);
   }for(o=c(a);!o;){
    if(e=e.parent(),e.is(n)||!e.length)return!1;o=c(e[0]);
   }if(o)return u(t(o),n);
  }return!1;
 }function f(e,n){
  return e?"string"==typeof e?(e=t(e,n),e.length?e:!1):e.jquery?e:!1:!1;
 }function h(t){
  for(var e=t.innerHeight(),n=["paddingTop","paddingBottom"],r=0,o=n.length;o>r;r++){
   var a=parseInt(t.css(n[r]),10);isNaN(a)&&(a=0),e-=a;
  }return e;
 }if(!t.fn.dotdotdot){
  t.fn.dotdotdot=function(e){
   if(0==this.length)return (t.fn.dotdotdot.debug("No element found for \""+this.selector+"\"."), this);if(this.length>1)return this.each(function(){
    t(this).dotdotdot(e);
   });var o=this;o.data("dotdotdot")&&o.trigger("destroy.dot"),o.data("dotdotdot-style",o.attr("style")||""),o.css("word-wrap","break-word"),"nowrap"===o.css("white-space")&&o.css("white-space","normal"),o.bind_events=function(){
    return (o.bind("update.dot",function(e,d){
     e.preventDefault(),e.stopPropagation(),l.maxHeight="number"==typeof l.height?l.height:h(o),l.maxHeight+=l.tolerance,"undefined"!=typeof d&&(("string"==typeof d||d instanceof HTMLElement)&&(d=t("<div />").append(d).contents()),d instanceof t&&(i=d)),g=o.wrapInner("<div class=\"dotdotdot\" />").children(),g.contents().detach().end().append(i.clone(!0)).find("br").replaceWith("  <br />  ").end().css({height: "auto",width: "auto",border: "none",padding: 0,margin: 0});var c=!1,u=!1;return (s.afterElement&&(c=s.afterElement.clone(!0),c.show(),s.afterElement.detach()), a(g,l)&&(u="children"==l.wrap?n(g,l,c):r(g,o,g,l,c)), g.replaceWith(g.contents()), g=null, t.isFunction(l.callback)&&l.callback.call(o[0],u,i), s.isTruncated=u, u);
    }).bind("isTruncated.dot",function(t,e){
     return (t.preventDefault(), t.stopPropagation(), "function"==typeof e&&e.call(o[0],s.isTruncated), s.isTruncated);
    }).bind("originalContent.dot",function(t,e){
     return (t.preventDefault(), t.stopPropagation(), "function"==typeof e&&e.call(o[0],i), i);
    }).bind("destroy.dot",function(t){
     t.preventDefault(),t.stopPropagation(),o.unwatch().unbind_events().contents().detach().end().append(i).attr("style",o.data("dotdotdot-style")||"").data("dotdotdot",!1);
    }), o);
   },o.unbind_events=function(){
    return (o.unbind(".dot"), o);
   },o.watch=function(){
    if(o.unwatch(),"window"==l.watch){
     var e=t(window),n=e.width(),r=e.height();e.bind("resize.dot"+s.dotId,function(){
      n==e.width()&&r==e.height()&&l.windowResizeFix||(n=e.width(),r=e.height(),u&&clearInterval(u),u=setTimeout(function(){
       o.trigger("update.dot");
      },100));
     });
    }else c=d(o),u=setInterval(function(){
     if(o.is(":visible")){
      var t=d(o);(c.width!=t.width||c.height!=t.height)&&(o.trigger("update.dot"),c=t);
     }
    },500);return o;
   },o.unwatch=function(){
    return (t(window).unbind("resize.dot"+s.dotId), u&&clearInterval(u), o);
   };var i=o.contents(),l=t.extend(!0,{},t.fn.dotdotdot.defaults,e),s={},c={},u=null,g=null;return (l.lastCharacter.remove instanceof Array||(l.lastCharacter.remove=t.fn.dotdotdot.defaultArrays.lastCharacter.remove), l.lastCharacter.noEllipsis instanceof Array||(l.lastCharacter.noEllipsis=t.fn.dotdotdot.defaultArrays.lastCharacter.noEllipsis), s.afterElement=f(l.after,o), s.isTruncated=!1, s.dotId=p++, o.data("dotdotdot",!0).bind_events().trigger("update.dot"), l.watch&&o.watch(), o);
  },t.fn.dotdotdot.defaults={ellipsis: "... ",wrap: "word",fallbackToLetter: !0,lastCharacter: {},tolerance: 0,callback: null,after: null,height: null,watch: !1,windowResizeFix: !0},t.fn.dotdotdot.defaultArrays={lastCharacter: {remove: [" ","　",",",";",".","!","?"],noEllipsis: []}},t.fn.dotdotdot.debug=function(){};var p=1,g=t.fn.html;t.fn.html=function(n){
   return n!=e&&!t.isFunction(n)&&this.data("dotdotdot")?this.trigger("update",[n]):g.apply(this,arguments);
  };var v=t.fn.text;t.fn.text=function(n){
   return n!=e&&!t.isFunction(n)&&this.data("dotdotdot")?(n=t("<div />").text(n).html(),this.trigger("update",[n])):v.apply(this,arguments);
  }
 }
}(jQuery);
function Feed(){
    this.win = null;
    this.desktop = null;

    if(view.$.hasClass("event-grid-feed") || view.$.hasClass("grid-feed")){
        setTimeout(function(){
            this.init.call(this, Services("pagetools"));
        }.bind(this));
    }
}

Feed.prototype = {

    init: function(pagetools){
        var self = this;

        this.win = pagetools.window._element;

        this.checkDimension();
        this.ellipsis();

        this.win.resize(function(event){
            self.checkDimension();
            self.ellipsis();
        });
    },

    checkDimension: function(){
        this.desktop = (this.win.width() < 752) ? false : true;
    },

    ellipsis: function(){
        if(view.$.hasClass("event-grid-feed") || view.$.hasClass("grid-feed")){
            $(view.$.find("header")).dotdotdot({
                ellipsis: "..."
            });

            $(view.$.find("main")).dotdotdot({
                ellipsis: "..."
            });
        }
    }


}

return Feed;
});
}).apply(window);/**!!<[ModuleFeed_com]!!**/
/**!![ModuleArticles_com]>!!**/
(function(){
registerModule("ModuleArticles", "com", function() {
function DiaryModule(){
  this.init();
}

DiaryModule.prototype = {

  construct: DiaryModule,

  init: function(){
    this.bindEvents();
  },

  bindEvents: function(){
    var self = this;

    $(".calendar-bt").on("click", function(){
      self.buildOverlay($(this));
    });
  },

  buildOverlay: function(diary){
    var self = this;
    var elHtml = diary.closest(".diary").find(".popup-content").html();
    var $element;

    var config = {
                  moduleClass: "module-articles",                   
                  afterInit: function (element) {
                    if (element) {
                      $element = $(element);
                      $element.html(elHtml);
                    }
                  }
              };

    var overlay = new (Helpers("overlay"))(config);
  }

};
var dom = parent;

function PdfModule() {
    this.win = null;

    setTimeout(function() {
        this.init.call(this, Services("pagetools"));
    }.bind(this));
}

PdfModule.prototype = {

    construct: PdfModule,

    init: function(pagetools) {
        this.parser();
        this.win = pagetools.window._element;
        this.bindOuterEvents();
    },

    // not modal events binding
    bindOuterEvents: function() {
        var self = this;
        $(".download-pdf").off().on("click", function(e) {
            e.preventDefault();
            if (!view.$.find(".overlay").length) {
                self.buildOverlay($(this));
            }
        });
    },

    // modal events binding if overlay opened
    bindOverlayEvents: function(element) {
        var self = this;

        this.bindCustomCheckboxes(element);

        element.find(".preview-doc").off().on("click", function(e) {
            e.preventDefault();
            self.preview();
        });

        element.find(".email-doc").off().on("click", function(e) {
            e.preventDefault();
            self.email(element);
        });
    },

    buildOverlay: function(pdf) {
        var self = this;
        var elHtml = pdf.closest(".pdf").find(".popup-content").html();
        var $element;
        var config = {
            moduleClass: "module-articles",
            afterInit: function(element) {
                if (element) {
                    $element = $(element);
                    $element.html(elHtml);
                    self.bindOverlayEvents(element);
                }
            }
        };

        var overlay = new(Helpers("overlay"))(config);
    },



    bindCustomCheckboxes: function(element) {
        var handleClick = function(e) {
            var obj = $(e.currentTarget);

            obj.toggleClass("checked");
            toggleCheckbox(obj);
            obj.nextAll(".icon").toggleClass("pdfgrey");
        }
        var setDefaultState = function(obj) {
            toggleCheckbox(obj);
        }
        var toggleCheckbox = function(obj) {
            var checkbox = obj.parent().find("input[type=checkbox].custom");
            if (obj.hasClass("checked")) {
                checkbox.prop("checked", true);
            } else {
                checkbox.prop("checked", false);
            }
        }
        var self = this;
        this.checkboxes = [];
        element.find("span.checkbox.custom").each(function() {
            setDefaultState($(this));
            $(this).on("click", handleClick.bind(this));
            self.checkboxes.push($(this));
        });
    },



    preview: function() {
        var self = this;
        var optionsData = [];
        $.each(this.checkboxes, function(i, checkbox) {
            var url = checkbox.attr("data-url");
            if (checkbox.hasClass("checked"))
                optionsData.push(url);
        });
        $.each(optionsData, function(i, link) {
            //self.win.open("http://www.w3schools.com");
            //self.win.open(link,'_blank');        
            dom.open(link, "_blank");
        });
    },

    parser: function(){
        "object"!=typeof JSON&&(JSON={}),function(){
            "use strict";function f(t){
                return 10>t?"0"+t:t;
            }function quote(t){
                return (escapable.lastIndex=0, escapable.test(t)?"\""+t.replace(escapable,function(t){
                    var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4);
                })+"\"":"\""+t+"\"");
            }function str(t,e){
                var n,r,o,f,u,i=gap,p=e[t];switch(p&&"object"==typeof p&&"function"==typeof p.toJSON&&(p=p.toJSON(t)),"function"==typeof rep&&(p=rep.call(e,t,p)),typeof p){case"string":return quote(p);case"number":return isFinite(p)?String(p):"null";case"boolean":case"null":return String(p);case"object":if(!p)return"null";if(gap+=indent,u=[],"[object Array]"===Object.prototype.toString.apply(p)){
                    for(f=p.length,n=0;f>n;n+=1)u[n]=str(n,p)||"null";return (o=0===u.length?"[]":gap?"[\n"+gap+u.join(",\n"+gap)+"\n"+i+"]":"["+u.join(",")+"]", gap=i, o);
                }if(rep&&"object"==typeof rep)for(f=rep.length,n=0;f>n;n+=1)"string"==typeof rep[n]&&(r=rep[n],o=str(r,p),o&&u.push(quote(r)+(gap?": ":":")+o));else for(r in p)Object.prototype.hasOwnProperty.call(p,r)&&(o=str(r,p),o&&u.push(quote(r)+(gap?": ":":")+o));return (o=0===u.length?"{}":gap?"{\n"+gap+u.join(",\n"+gap)+"\n"+i+"}":"{"+u.join(",")+"}", gap=i, o)}
            }"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){
                return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null;
            },String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){
                return this.valueOf();
            });var cx,escapable,gap,indent,meta,rep;"function"!=typeof JSON.stringify&&(escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,meta={"\b": "\\b","\t": "\\t","\n": "\\n","\f": "\\f","\r": "\\r","\"": "\\\"","\\": "\\\\"},JSON.stringify=function(t,e,n){
                var r;if(gap="",indent="","number"==typeof n)for(r=0;n>r;r+=1)indent+=" ";else"string"==typeof n&&(indent=n);if(rep=e,e&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw new Error("JSON.stringify");return str("",{"": t});
            }),"function"!=typeof JSON.parse&&(cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,JSON.parse=function(text,reviver){
                function walk(t,e){
                    var n,r,o=t[e];if(o&&"object"==typeof o)for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&(r=walk(o,n),void 0!==r?o[n]=r:delete o[n]);return reviver.call(t,e,o);
                }var j;if(text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(t){
                    return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4);
                })),/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return (j=eval("("+text+")"), "function"==typeof reviver?walk({"": j},""):j);throw new SyntaxError("JSON.parse");
            });
        }();
    },

    // send documents on users email
    email: function(element) {
        var optionsData = {
            Download: []
        };

        var email = element.find(".clientmail").val();
        var url = element.find("form").attr("action");

        element.find(".confirmation-email a").html(email);
        setTimeout(function() {
            element.find(".confirmation-email").css({
                visibility: "visible"
            });
        }, 500);


        $.each(this.checkboxes, function(i, checkbox) {
            var name = checkbox.attr("data-url");
            var value = checkbox.next().val();
            if (checkbox.hasClass("checked"))
                optionsData.Download.push(value);
        });

        optionsData.EmailAddress = email;
        optionsData.Action = "EmailDocuments";

        $.ajax({
            url: url,
            cache: false,
            type: "POST",
            dataType: "json",
            contentType: "application/json",
            processData: false,
            data: JSON.stringify(optionsData),
            xhrFields: {
                withCredentials: true
            }
        });

        /*    
        $.ajax({
            url: url,
            cache: false,
            type: 'POST',
            dataType: 'json',
            contentType: 'application/json, charset=utf-8',
            data: JSON.stringify(optionsData)
        });
        */;
    }
};
(function(){
  /**
  @license Sticky-kit v1.0.4 | WTFPL | Leaf Corcoran 2014 | http://leafo.net
   */

  (function() {
    var win;



    win = $(dom);

    $.fn.stick_in_parent = function(opts) {
      var elm, inner_scrolling, offset_top, parent_selector, sticky_class, _fn, _i, _len;
      if (opts == null) {
        opts = {};
      }
      sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, parent_selector = opts.parent, offset_top = opts.offset_top;
      if (offset_top == null) {
        offset_top = 0;
      }
      if (parent_selector == null) {
        parent_selector = void 0;
      }
      if (inner_scrolling == null) {
        inner_scrolling = true;
      }
      if (sticky_class == null) {
        sticky_class = "is_stuck";
      }
      _fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float) {
        var bottomed, detach, fixed, last_pos, offset, parent, recalc, recalc_and_tick, spacer, tick;
        if (elm.data("sticky_kit")) {
          return;
        }
        elm.data("sticky_kit", true);
        parent = elm.parent();
        if (parent_selector != null) {
          parent = parent.closest(parent_selector);
        }
        if (!parent.length) {
          throw "failed to find stick parent";
        }
        fixed = false;
        bottomed = false;
        spacer = $("<div />");
        spacer.css("position", elm.css("position"));
        recalc = function() {
          var border_top, padding_top, restore;
          border_top = parseInt(parent.css("border-top-width"), 10);
          padding_top = parseInt(parent.css("padding-top"), 10);
          padding_bottom = parseInt(parent.css("padding-bottom"), 10);
          parent_top = parent.offset().top + border_top + padding_top;
          parent_height = parent.height();
          restore = fixed ? (fixed = false, bottomed = false, elm.insertAfter(spacer).css({
            position: "",
            top: "",
            width: "",
            bottom: ""
          }), spacer.detach(), true) : void 0;
          top = elm.offset().top - parseInt(elm.css("margin-top"), 10) - offset_top;
          height = elm.outerHeight(true);
          el_float = elm.css("float");
          spacer.css({
            width: elm.outerWidth(true),
            height: height,
            display: elm.css("display"),
            "vertical-align": elm.css("vertical-align"),
            "float": el_float
          });
          if (restore) {
            return tick();
          }
        };
        recalc();
        if (height === parent_height) {
          return;
        }
        last_pos = void 0;
        offset = offset_top;
        tick = function() {
          var css, delta, scroll, will_bottom, win_height;
          scroll = win.scrollTop();
          if (last_pos != null) {
            delta = scroll - last_pos;
          }
          last_pos = scroll;
          if (fixed) {
            will_bottom = scroll + height + offset > parent_height + parent_top;
            if (bottomed && !will_bottom) {
              bottomed = false;
              elm.css({
                position: "fixed",
                bottom: "",
                top: offset
              }).trigger("sticky_kit:unbottom");
            }
            if (scroll < top) {
              fixed = false;
              offset = offset_top;
              if (el_float === "left" || el_float === "right") {
                elm.insertAfter(spacer);
              }
              spacer.detach();
              css = {
                position: "",
                width: "",
                top: ""
              };
              elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
            }
            if (inner_scrolling) {
              win_height = win.height();
              if (height > win_height) {
                if (!bottomed) {
                  offset -= delta;
                  offset = Math.max(win_height - height, offset);
                  offset = Math.min(offset_top, offset);
                  if (fixed) {
                    elm.css({
                      top: offset + "px"
                    });
                  }
                }
              }
            }
          } else {
            if (scroll > top) {
              fixed = true;
              css = {
                position: "fixed",
                top: offset
              };
              css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
              elm.css(css).addClass(sticky_class).after(spacer);
              if (el_float === "left" || el_float === "right") {
                spacer.append(elm);
              }
              elm.trigger("sticky_kit:stick");
            }
          }
          if (fixed) {
            if (will_bottom == null) {
              will_bottom = scroll + height + offset > parent_height + parent_top;
            }
            if (!bottomed && will_bottom) {
              bottomed = true;
              if (parent.css("position") === "static") {
                parent.css({
                  position: "relative"
                });
              }
              return elm.css({
                position: "absolute",
                bottom: padding_bottom,
                top: "auto"
              }).trigger("sticky_kit:bottom");
            }
          }
        };
        recalc_and_tick = function() {
          recalc();
          return tick();
        };
        detach = function() {
          win.off("scroll", tick);
          $(document.body).off("sticky_kit:recalc", recalc_and_tick);
          elm.off("sticky_kit:detach", detach);
          elm.removeData("sticky_kit");
          elm.css({
            position: "",
            bottom: "",
            top: ""
          });
          parent.position("position", "");
          if (fixed) {
            elm.insertAfter(spacer).removeClass(sticky_class);
            return spacer.remove();
          }
        };
        win.on("touchmove", tick);
        win.on("scroll", tick);
        win.on("resize", recalc_and_tick);
        $(document.body).on("sticky_kit:recalc", recalc_and_tick);
        elm.on("sticky_kit:detach", detach);
        return setTimeout(tick, 0);
      };
      for (_i = 0, _len = this.length; _i < _len; _i++) {
        elm = this[_i];
        _fn($(elm));
      }
      return this;
    };
  }).call(this);
})();
var dom = parent;

function FilterModule(){
    this.win = null;
    this.desktop = null;
    this.sections = {};
    //this.init();
    this.$window = null;

    setTimeout(function() {
        this.init.call(this, Services("pagetools"));
    }.bind(this));
}

FilterModule.prototype = {

    construct: FilterModule,

    init: function(pagetools){
        var self = this;
        this.win = pagetools.window._element;
        this.collectMonths();
        this.checkDimension();
        this.bindEvents();
        this.checkWidth();

        this.win.resize(function(event){
            self.checkWidth();
        });

        var diary = new DiaryModule();
        var pdf = new PdfModule();
    },

    checkWidth: function(){
        if (this.win.width() < 750 && $(".listed-elements section").length) {
            $("section").find("h3").stick_in_parent({offset_top: 50});
        }
        else{
            $("section").find("h3").trigger("sticky_kit:detach");
        }
    },    

    checkDimension: function(){
        this.desktop = (this.win.width() < 750) ? false : true;
    },

    bindEvents: function(){
        var self = this;
        // filter showing/hiding categories and years
        $(".sub-title").off().on("click", function(){
            self.checkDimension();
            // desktop full filter
            if(self.desktop && !view.$.find(".filter").hasClass("date-format")){
                self.toggleDesktopContent();
            }// mobile 
            else if(!self.desktop){
                self.toggleMobileData();
            }//if desktop data-only
            else{
                self.toggleDesktopDataOnly();
            }
        });
        //toggle category list on mobile
        $(".mb-category-input").off().on("click", function(){
            self.checkDimension();
            if(!self.desktop) self.toggleMobileCategory();
        });
        //scroll top
        $("nav").off().on("click", function(){
            dom.$("body, html").animate({
                scrollTop: $(".date-input").offset().top
            }, 500);
        });
        // scroll to months
        $(".filter-footer .active").off().on("click", function(){
            self.scrollToMonth($(this));
        });
    },

    // checks months in each section and add class active to months in filter 
    collectMonths: function(){
        if(!(".filter-footer").length) return;
        var self = this;
        $(".filter-footer li").removeClass("active");
        $(".listed-elements section").each(function(i){
            var month = $(this).data("month");
            $(".filter-footer").find("."+month).addClass("active");
        });
    },

    // filter : different transition effects
    toggleDesktopContent: function(){
        var content = view.$.find(".filter-toggle");
        content.toggleClass("transition");
        view.$.find(".sub-title .arrow").toggleClass("cross");
        setTimeout(function(){
            $(".sub-title").toggleClass("no-border");
        }, 450);
    },

    toggleMobileData: function(){
        var data = view.$.find(".data-picker");
        data.toggleClass("transition-mobile");
        view.$.find(".sub-title .arrow").toggleClass("arrow-bottom");
    },

    toggleMobileCategory: function(){
        var category = view.$.find(".categories-container");
        category.toggleClass("transition-mobile");
        view.$.find(".mb-category-input .arrow").toggleClass("arrow-bottom");
    },

    toggleDesktopDataOnly: function(){
        var content = view.$.find(".filter-toggle");
        view.$.toggleClass("selected");
        content.toggleClass("transition-data-only");
        this.bindEvents();
    },

    //scrolls to months clicked
    scrollToMonth: function(el){
        var monthClass = this.getMonth(el);
        dom.$("body, html").animate({
            scrollTop: $(".listed-elements").find("[data-month='" + monthClass + "']").offset().top
        }, 500);
    },

    getMonth: function(el){
        var string = el.attr("class");
        var array = string.split(" ");
        var month;
        $.each(array, function(index, value) {
            if(value !== "active" && value.length === 3){
                month = value;
            }
        });
        return month;
    },

    sendYear: function(year){
        var yearSelected = parseInt(year.html());
        $.ajax({
            url: "",
            type: "POST",
            data: {
                year: yearSelected
            }
        });
    }   	

};

return FilterModule;
});
}).apply(window);/**!!<[ModuleArticles_com]!!**/
/**!![ModuleArticle_com]>!!**/
(function(){
registerModule("ModuleArticle", "com", function() {
/* not in use as we are using cookies
    var dom = parent;

    function SingleArticleModule(){ 
   
        this.init();                
    }

    SingleArticleModule.prototype = {
        construct: SingleArticleModule,

        init: function(){           
            var self = this; 
            this.getCategoryFromUrl();
        },

        getCategoryFromUrl: function(){
            function getParameterByName(name) {                
                name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
                var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
                var results = regex.exec(dom.location.href);
                return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
            }
            var category = getParameterByName('category');          
            this.addCategoryToLink(category);
        },

        addCategoryToLink: function(category){
            
            if (category!==""){
                var current=view.$.find('nav a').attr('href');
                view.$.find('nav a').attr('href', current+'/?category='+category);       	

            }
       
        }  	

    };

return SingleArticleModule;
*/























;
});
}).apply(window);/**!!<[ModuleArticle_com]!!**/
/**!![ModuleFaq_com]>!!**/
(function(){
registerModule("ModuleFaq", "com", function() {
function Faq(){
    this.tabPanel = $("ul.tabs");
    this.desktop = null;
    this.currentView = null;
    this.win = null;

    setTimeout(function() {
        this.init.call(this, Services("pagetools"));
    }.bind(this));
}

Faq.prototype = {

    construct: Faq,

    init: function(pagetools){
        var self = this;
        this.win = pagetools.window._element;
        this.checkDimension();
        this.win.resize(function(event){
            self.checkDimension();
        });
    },

    bindEvents: function(){
        var self = this;
        this.desktop ? this.bindDesktopEvents() : this.bindMobileEvents();
        $(".question-tab").off().on("click", function(){
            self.selectQuestion($(this));
        });
    },

    bindMobileEvents: function(){
        var self = this;
        this.tabPanel.find("li label").off().on("click", function(){
            self.selectTabMobile($(this));
        });
    },

    bindDesktopEvents: function(){
        var self = this;
        this.tabPanel.find("li label").off();
        this.tabPanel.find("li").off().on("click", function(){
            self.selectTabDesktop($(this));
        });
    },

    checkDimension: function(){
        this.desktop = (this.win.width() < 750) ? false : true;
        if(this.currentView != this.desktop){
            this.currentView = this.desktop;
            this.createView();
            this.preselection();
            this.bindEvents();
        }
    },

    getParameterByName: function(name){
        name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
        var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
        var results = regex.exec(this.win[0].location.href);
        return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
    },

    preselection: function(){
        // if query string get topic and question
        //else setDefault State            
        if(this.categoryExist()){
            this.preselectFromQuery();
        }
        else{
            this.desktop ? this.setDefaultStateDesktop() : this.setDefaultStateMobile();
        }
    },

    preselectFromQuery: function(){
        var category = this.getParameterByName("category").replace(/\ /g,"_");
        var question = this.getParameterByName("question");
        var element = $(".tabs").find("[data-tab='"+category+"']");

        if(this.desktop){
            this.selectTabDesktop(element);
        } 
        else{
            this.setDefaultStateMobile();
            this.selectTabMobile(element.find("label"));
        }
        var qelement = $("#"+category).find("[data-question='"+question+"']");
        this.selectQuestion(qelement);
    },

    categoryExist: function(){
        var catName = this.getParameterByName("category").replace(/\ /g,"_");
        return ($(".tabs").find("[data-tab='"+catName+"']").length > 0) ? true : false;
    },

    selectTabDesktop: function(tab){
        if(this.desktop){
            var topic = tab.attr("data-tab");
            $("section.questions ul").addClass("hidden");
            $("section.questions #"+topic).removeClass("hidden");
            this.tabPanel.find("li").removeClass("selected");
            tab.addClass("selected");
        }
    },

    selectTabMobile: function(label){
        label.next().toggleClass("hidden");
        label.toggleClass("down");
    }, 

    selectQuestion: function(qclicked){
        qclicked.toggleClass("open");
    },

    setDefaultStateDesktop: function(){
        // find data-tab of first label 
        var firstTab = this.tabPanel.find("li").first().attr("data-tab");
        this.tabPanel.find("[data-tab='"+firstTab+"']").addClass("selected");
        this.resetQuestions();
        $(".tabs-content").addClass("hidden");
        $("#"+firstTab).removeClass("hidden");
    },

    setDefaultStateMobile: function(){
        this.resetQuestions();
        this.resetTabs();
        this.hideQuestions();
    },

    resetTabs: function(){
        this.tabPanel.find("li").removeClass("selected");
        this.tabPanel.find("li").find("label").removeClass("down");
    },

    resetQuestions: function(){
        $(".tabs-content li").removeClass("open");
    },

    showAllQuestions: function(){
        $(".tabs-content").removeClass("hidden");
    },

    hideQuestions: function(){
        $(".tabs-content").addClass("hidden");
    },

    createView: function(){
        this.desktop ? this.createDesktopView() : this.createMobileView();
    },

    createDesktopView: function(){
        this.tabPanel.find("li").each(function(i){
            var questions = $(this).find(".tabs-content");
            $("section.questions").append(questions);
        });
        this.setDefaultStateDesktop();
    },

    createMobileView: function(){
        this.tabPanel.find("li").each(function(i){
            var topic = $(this).attr("data-tab");
            var questions = $("section.questions").find("#"+topic);
            $(this).append(questions);
        });
    }
};

return Faq;
});
}).apply(window);/**!!<[ModuleFaq_com]!!**/
/**!![ModuleFaqCta_com]>!!**/
(function(){
registerModule("ModuleFaqCta", "com", function() {
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */;
});
}).apply(window);/**!!<[ModuleFaqCta_com]!!**/
/**!![ModuleAlsoSee_com]>!!**/
(function(){
registerModule("ModuleAlsoSee", "com", function() {
var $__Object$defineProperties = Object.defineProperties;
var $__Object$defineProperty = Object.defineProperty;
var $__Object$create = Object.create;
var $__Object$getPrototypeOf = Object.getPrototypeOf;
var Carousel = Helpers("carousel");

/**
 * @private
 */
function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        clearTimeout(timeout);
        timeout = setTimeout(function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        }, wait);
        if (immediate && !timeout) func.apply(context, args);
    };
}

var AlsoSee = function($__super) {
    "use strict";

    function AlsoSee() {
        this.$scope = view.$.find(".container");
        this.config = {
		   	scope: this.$scope,
		    renderPagination: false,
		    itemsWidth: "auto"
		};
        setTimeout(function() {
            this.pagetools = Services("pagetools");
            $__Object$getPrototypeOf(AlsoSee.prototype).constructor.call(this, this.config);
        }.bind(this));
    }

    AlsoSee.__proto__ = ($__super !== null ? $__super : Function.prototype);
    AlsoSee.prototype = $__Object$create(($__super !== null ? $__super.prototype : null));

    $__Object$defineProperty(AlsoSee.prototype, "constructor", {
        value: AlsoSee
    });

    $__Object$defineProperties(AlsoSee.prototype, {
        init: {
            value: function() {
                this._window = this.pagetools.window._element[0];
                this.$window = this.pagetools.window._element;

                if (this.count < 3) {
                    // Max amount of items permited
                    this.config.listWidth = this.getItemsTotalWidth();
                }

                if (this.isMobile) {
                    this.startCarousel();
                }

                this.$window.on("resize", function(event) {
                    if (this.isMobile) {
                        if (!this.$list.parent().hasClass("helper-carousel")) {
                            this.startCarousel();
                        }
                        this.toggleArrows();
                    } else if (this.$list.parent().hasClass("helper-carousel")) {
                        this.stopCarousel();
                    }
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        startCarousel: {
            value: function() {
                this.currentItem = 1;
                // Wrap carousel
                this.$list.wrap("<div class=\"slides-wrapper\" />");

                // Add helper class
                this.$list.parent(".slides-wrapper").addClass("helper-carousel");

                // Adjust sizes
                var itemsWidth = this.$items.first().find("img").css("width") || this.config.itemsWidth,
                    listWidth = this.getItemsTotalWidth();

                this.$items.width(itemsWidth);
                this.$list.width(listWidth);

                // Render navigation arrows
                var arrowsHtml = this.Templates._arrows();
                if (!this.$navigationNext) {
                    this.$scope.append($(arrowsHtml));
                    // Event targets
                    this.$navigationPrevious = this.$scope.find(".nav-button.prev");
                    this.$navigationNext = this.$scope.find(".nav-button.next");
                }

                this.$navigationPrevious.hide();
                this.$navigationNext.show();

                if (!this.carouselIsBound) {
                    this.bindCarousel();
                }
            },

            enumerable: false,
            writable: true
        },

        stopCarousel: {
            value: function() {
                // Unwrap carousel
                this.$list.unwrap("<div />");
                this.$list.width("");
                this.$items.width("");
                this.updateOffset(0);
                this.$navigationPrevious.hide();
                this.$navigationNext.hide();
            },

            enumerable: false,
            writable: true
        },

        bindCarousel: {
            value: function() {
                // Set event handlers
                this.$navigationPrevious.on("click", function(e) {
                    e.preventDefault();
                    this.previousItem();
                    this.$navigationNext.show();
                }.bind(this));

                this.$navigationNext.on("click", function(e) {
                    e.preventDefault();
                    this.nextItem();
                    this.$navigationPrevious.show();
                }.bind(this));
                this.carouselIsBound = true;
            },

            enumerable: false,
            writable: true
        },

        toggleArrows: {
            value: function() {
                if (this.getItemsTotalWidth() > this.$list.parent().width() && this.currentItem === 1) {
                    this.$navigationNext.show();
                } else {
                    this.$navigationNext.hide();
                }
            },

            enumerable: false,
            writable: true
        },

        previousItem: {
            value: function() {
                var $item = $(this.$items[this.currentItem - 1]),
                    itemPosition = $item.index(),
                    itemMargin = this.$items.last().css("marginLeft"),
                    itemOuterWidth = $item.width() + (itemMargin.replace("px","") * 1),
                    containerWidth = this.$list.parent().width(),
                    currentListOffset = parseFloat(this.$list.css("left").replace("px","")) * -1 || 0,
                    offset = 0;

                if (this.config.listWidth - containerWidth < itemOuterWidth) {
                    offset = this.config.listWidth - containerWidth;
                } else if (this.currentItem === this.count) {
                    offset = itemOuterWidth;
                } else {
                    offset = itemOuterWidth;
                }

                if (this.currentItem > 2) {
                    this.setCurrentItem(this.currentItem - 1);
                    this.updateOffset(offset);
                } else {
                    this.updateOffset(0);
                    this.setCurrentItem(1);
                }

                if (this.currentItem === 1) {
                    this.$navigationPrevious.hide();
                }
            },

            enumerable: false,
            writable: true
        },

        nextItem: {
            value: function(multiplier) {
                var $item = $(this.$items[this.currentItem - 1]),
                    itemPosition = $item.index(),
                    itemMargin = this.$items.last().css("marginLeft"),
                    itemOuterWidth = $item.width() + (itemMargin.replace("px","") * 1),
                    containerWidth = this.$list.parent().width(),
                    currentListOffset = parseFloat(this.$list.css("left").replace("px","")) * -1 || 0,
                    offset = 0;

                // Check if the slides have enough space to offset more than once
                // When the next item is the last one, offset just the remainging of slides
                // Otherwise just offset the width of one item at a time
                if (this.config.listWidth - containerWidth < itemOuterWidth) {
                    offset = this.config.listWidth - containerWidth;
                    this.$navigationNext.hide();
                } else if (this.currentItem === this.count - 1) {
                    offset = itemOuterWidth;
                    this.$navigationNext.hide();
                } else {
                    offset = itemOuterWidth;
                }
                if (this.currentItem === this.count) {
                    this.setCurrentItem(this.currentItem);
                    this.$navigationNext.hide();
                } else {
                    this.setCurrentItem(this.currentItem + 1);
                    this.updateOffset(-1 * offset);
                }
            },

            enumerable: false,
            writable: true
        },

        updateOffset: {
            value: function(offset) {
                this.offset = !!offset ? this.offset + offset : 0;
                this.$list.animate({
                    left: this.offset + "px"
                }, this.config.rotationDuration);
            },

            enumerable: false,
            writable: true
        },

        setCurrentItem: {
            value: function(index) {
                this.currentItem = index;
            },

            enumerable: false,
            writable: true
        },

        isMobile: {
            value: function() {
                var width = this._window.innerWidth || this._window.document.documentElement.clientWidth || this._window.document.body.clientWidth;
                return width < 768;
            },

            enumerable: false,
            writable: true
        },

        getItemsTotalWidth: {
            value: function() {
                var $slides = this.$items,
                    slidesWidth = 0;
                $slides.each(function(i, item) {
                    slidesWidth += $(item).outerWidth(true);
                });
                return slidesWidth;
            },

            enumerable: false,
            writable: true
        }
    });

    return AlsoSee;
}(Carousel);

return AlsoSee;
});
}).apply(window);/**!!<[ModuleAlsoSee_com]!!**/
/**!![ModuleGallery_com]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_gallery"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, buffer = "        <li>\n            <div class=\"content\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.youTube : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.program(4, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "                <div class=\"description\">";
  stack1 = lambda((depth0 != null ? depth0.description : depth0), depth0);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</div>\n            </div>\n        </li>\n";
},"2":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                <div class=\"video-wrapper\">\n                    <img title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" alt=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" data-media=\"https://img.youtube.com/vi/"
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "/0.jpg\" data-video=\"true\" data-render-video=\""
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "\">\n                    <a href=\"#\" class=\"video-link\"></a>\n                    <div class=\"player-store\"></div>\n                </div>\n";
},"4":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                <img title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" alt=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" data-media=\""
    + escapeExpression(lambda((depth0 != null ? depth0.image : depth0), depth0))
    + "\">\n";
},"6":function(depth0,helpers,partials,data) {
  var stack1, buffer = "                <li>\n";
  stack1 = helpers.each.call(depth0, depth0, {"name":"each","hash":{},"fn":this.program(7, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                </li>\n";
},"7":function(depth0,helpers,partials,data) {
  var stack1, buffer = "                    <a href=\"javascript:\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.youTube : depth0), {"name":"if","hash":{},"fn":this.program(8, data),"inverse":this.program(10, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                    </a>\n";
},"8":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        <img data-media=\"https://img.youtube.com/vi/"
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "/0.jpg\" data-video=\"true\">\n";
},"10":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        <img data-media=\""
    + escapeExpression(lambda((depth0 != null ? depth0.image : depth0), depth0))
    + "\">\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "<div class=\"gallery\" data-gallery-d=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\">\n    <div class=\"gallery-details res-1280-cols-10 res-1024-cols-10 res-752-cols-10\">\n        <h2 class=\"title\">"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</h2>\n        <div class=\"description\">";
  stack1 = ((helper = (helper = helpers.description || (depth0 != null ? depth0.description : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"description","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  buffer += "</div>\n    </div>\n    <ul class=\"slides\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "    </ul>\n    <div class=\"thumbnails\">\n        <div class=\"slides-wrapper\">\n            <ul class=\"slides\">\n";
  stack1 = ((helpers.grouped_each || (depth0 && depth0.grouped_each) || helperMissing).call(depth0, 5, (depth0 != null ? depth0.items : depth0), {"name":"grouped_each","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "            </ul>\n        </div>\n    </div>\n    <div class=\"info\"></div>\n</div>";
},"useData":true});
this["templates"]["_info"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"info\">\n    <span class=\"current\">"
    + escapeExpression(((helper = (helper = helpers.current || (depth0 != null ? depth0.current : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"current","hash":{},"data":data}) : helper)))
    + "</span>\n    <span class=\"total\">of "
    + escapeExpression(((helper = (helper = helpers.total || (depth0 != null ? depth0.total : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"total","hash":{},"data":data}) : helper)))
    + "</span>\n</div>";
},"useData":true});
this["templates"]["_tabs"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + " data-gallery-id=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\"><a title=\""
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "\" href=\"#\">"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</a></li>\n";
},"2":function(depth0,helpers,partials,data) {
  return "class=\"selected\"";
  },"4":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += " data-gallery-id=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\">";
  stack1 = ((helper = (helper = helpers.content || (depth0 != null ? depth0.content : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"content","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"tabs-select-wrapper\">\n	<a href=\"#\" class=\"tabs-select\" title=\"Open galleries select menu\"></a>\n</div>\n<ul class=\"helper-tabs level-1\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "</ul>\n<ul class=\"helper-tabs level-2\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</ul>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('ModuleGallery.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerModule("ModuleGallery", "com", function() {
/*
 * @module Gallery
 */

/**
 * @class Gallery
 * @classdesc Renders a tabbed gallery inside an overlay.
 *            This class depends on the following Helpers and Services.
 *                Helpers: overlay, gallery, tabs.
 *                Services: pagetools, youtubeIframeApi.
 */

var $__Object$defineProperties = Object.defineProperties;

var Gallery = function() {
    "use strict";

    function Gallery() {
        this.config = {
            scope: view.$,
            onItemNavigateStart: function(itemIndex) {
                this.currentItem = itemIndex;
                this.refreshInfo();
            }.bind(this)
        };

        //this.currentItem = 0;
        //this.clickedGalleryIndex = 0;
        setTimeout(function() {
            //this.pagetools = Services('pagetools');
            this.init();
        }.bind(this));
    }

    $__Object$defineProperties(Gallery.prototype, {
        init: {
            value: function() {
                new (Helpers("gallery-overlay"))(this.config);
                /*        var $galleryButtons = $(this.pagetools.body._element[0]).find('.open-gallery-overlay');
                        if (!!$galleryButtons.length) {
                            $galleryButtons.on('click', (event) => {
                                event.preventDefault();
                                var $this = $(event.currentTarget).is('a') ? $(event.currentTarget) : $(event.currentTarget).children('a'),
                                    galleriesUrl = $this.attr('href'),
                                    galleryId = galleriesUrl.match(/id=(\d+)/);
                                    galleryId = galleryId[1];

                                this.clickedGalleryId =  galleryId; // Store the clicked gallery to select correspondent tab
                                this.getGalleryData(galleriesUrl)
                                .done((data) => {
                                    this.renderGallery(data);
                                })
                                .fail((data) => {
                                    console.log('Galleries feed request failed');
                                });
                            });
                        } else {
                            console.log('There are no gallery links on the page');
                        }*/;
            },

            enumerable: false,
            writable: true
        },

        getGalleryData: {
            value: function(url) {
                //var dataUrl = url.match(/\/\?/) ? url.replace('?', 'json?') : url.replace('?', '/json?');
                var dataUrl = url.match(/\?/) ? url + "&json=1" : url + "?json=1";
                //var dataUrl = 'assets/galleries.json'; // Use locally
                return this.pagetools.window._element[0].$.ajax(dataUrl);
            },

            enumerable: false,
            writable: true
        },

        renderGallery: {
            value: function(galleryData) {
                if (typeof galleryData === "object") {
                    var tabsTemplate = {
                            "items": []
                        },
                        Templates = {
                            _gallery: Services("templateService").templates("ModuleGallery._gallery")
                        };
                    // Render each gallery template and add it to tabsTemplate
                    for (var i, i = 0; i < galleryData.items.length; i++) {
                        var temp = {
                            title: galleryData.items[i].title,
                            id: galleryData.items[i].id,
                            content: Templates._gallery(galleryData.items[i])
                        };
                        tabsTemplate.items.push(temp);
                    }

                    // Render the tabs template with the tabsTemplate object, that contains the galleries html
                    Templates._tabs = Services("templateService").templates("ModuleGallery._tabs");
                    var galleryTemplate = Templates._tabs(tabsTemplate);

                    // Create config to pass to the overlay helper. Contains the galleryTemplate, which has the tabsTemplate html.
                    // The tabsTemplate html already has the galleries html inside each tab.
                    var overlayConfig = {
                            moduleClass: "module-gallery",
                            afterInit: function(element) {
                                if (element) {
                                    var $element = $(element);

                                    $element.html(galleryTemplate);
                                    this.startGallery.call(this);
                                }
                            }.bind(this)
                        };
                    // Instantiate the overlay. After init, it will call the startGallery method to bind events.
                    this.overlayHelper = new (Helpers("overlay"))(overlayConfig);
                } else {
                    console.log("Galleries feed is undefined");
                }
            },

            enumerable: false,
            writable: true
        },

        startGallery: {
            value: function() {
                var $galleries;
                // Set the overlay scope element
                this.$overlayScope = this.overlayHelper.$elContent;

                // Get all the galleries inside the overlay element
                $galleries = this.$overlayScope.find(".gallery");

                // If the gallery overlay has only 1 gallery
                if ($galleries.length === 1) {
                    this.$overlayScope.addClass("single-gallery");
                }

                // Go through each gallery element in the overlay.
                // On each, instantiate a new gallery to bind all events and build it as a gallery
                $galleries.each(function(index, element) {
                    var $this = $(element),
                        $slides = $this.find(".slides"),
                        $slidesWrapper,
                        config = {
                            scope: $this,
                            itemCount: $slides.first().find("li").length,
                            onItemNavigateStart: function(itemIndex) {
                                this.currentItem = itemIndex;

                                this.refreshInfo.call(this, config.scope, config.itemCount);
                            }.bind(this)
                        };

                    element.gallery = new (Helpers("gallery"))(config);

                    // In case there's only 1 item in the gallery
                    if (config.itemCount === 1) {
                        $slidesWrapper = $slides;
                        $slidesWrapper.addClass("single-item");
                    } else {
                        $slidesWrapper = $this.find(".slides-wrapper");
                    }

                    // Hack
                    // Add grid template to each slides wrapper.
                    $slidesWrapper.addClass("res-1280-cols-10 res-1024-cols-10 res-752-cols-10");

                    // Refresh info displays the current item/total count in the page
                    // Generates the template to each gallery
                    this.refreshInfo(config.scope, config.itemCount);
                }.bind(this));

                this.startTabs();
            },

            enumerable: false,
            writable: true
        },

        refreshInfo: {
            value: function($scope, itemCount) {
                this.$info = $scope.children(".info");

                // We should be able to access templates using
                // Templates._info
                // But this is currently broken, hence the hack below
                var Templates = {
                    _info: Services("templateService").templates("ModuleGallery._info")
                };

                var infoHtml = Templates._info({
                    current: this.integerToTwoDigits(this.currentItem + 1),
                    total: this.integerToTwoDigits(itemCount)
                });

                if (!this.$info.length) {
                    $scope.append(infoHtml);
                } else {
                    this.$info.replaceWith(infoHtml);
                }
            },

            enumerable: false,
            writable: true
        },

        integerToTwoDigits: {
            value: function(integer) {
                return integer < 10 ? "0" + integer : integer.toString();
            },

            enumerable: false,
            writable: true
        },

        startTabs: {
            value: function() {
                var $tabSet = this.$overlayScope.find(".helper-tabs.level-1"),
                    $tabContentSet = this.$overlayScope.find(".helper-tabs.level-2"),
                    $tabs = $tabSet.children("li"),
                    tabOpenedByDefault = 0;

                // Gets the gallery corresponding to the clicked link to open by default
                $tabs.each(function(index, element) {
                    if ($(element).attr("data-gallery-id") === this.clickedGalleryId) {
                        tabOpenedByDefault = index;
                    }
                }.bind(this));

                this.tabsConfig = {
                    scope: this.$overlayScope,
                    defaultTabIndex: tabOpenedByDefault,
                    tabSet: $tabSet,
                    tabContentSet: $tabContentSet,
                    tabSelectMenu: this.$overlayScope.find(".tabs-select"),
                    onTabInit: function(index, element) {
                        this.postRenderMedia.call(this, element);
                    }.bind(this)
                };

                new (Helpers("tabs"))(this.tabsConfig);

                // Gets widths to do post render adjustments
                this.tabSetWidth = this.tabsConfig.tabSet.width();
                this.tabsWidth = this.getTabsWidth($tabs);

                this.setSelectedMobileTab();
                this.startMobileTabs();
            },

            enumerable: false,
            writable: true
        },

        getTabsWidth: {
            value: function($scope) {
                var width = 0;
                $scope.each(function(index, element) {
                    width += $(element).outerWidth(true);
                });
                return width;
            },

            enumerable: false,
            writable: true
        },

        setSelectedMobileTab: {
            value: function($scope) {
                var selectedTabText = $scope ? $scope.text() : this.tabsConfig.tabSet.find(".selected").children().text();
                this.tabsConfig.tabSelectMenu.text(selectedTabText);
            },

            enumerable: false,
            writable: true
        },

        startMobileTabs: {
            value: function() {
                this.bindMobileTabsEvents();
                this.toggleDesktopDropdownTabs();
            },

            enumerable: false,
            writable: true
        },

        bindMobileTabsEvents: {
            value: function() {
                this.tabsConfig.tabSelectMenu.on("click", function(event) {
                    event.preventDefault();
                    $(event.currentTarget).toggleClass("opened");
                    this.tabsConfig.tabSet.toggleClass("mobile-visible");
                }.bind(this));

                // When a tab is selected on dropdown mode, closes the dropdown
                this.tabsConfig.tabSet.find("a").on("click.tabSelectMenu", function(event) {
                    event.preventDefault();
                    this.setSelectedMobileTab($(event.currentTarget));
                    this.tabsConfig.tabSelectMenu.removeClass("opened");
                    this.tabsConfig.tabSet.removeClass("mobile-visible");
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        postRenderMedia: {
            value: function($scope) {
                if (!$scope.attr("data-media-rendered")) {
                    $scope.find("img").each(function(index, element) {
                        var $this = $(element),
                            mediaData = $this.data("media");

                        if ($this.attr("data-video") && $this.data("render-video")) {
                            this.bindVideoEvents($this.next(), $this.data("render-video"));
                        }
                        $this.attr("src", mediaData);
                    }.bind(this));
                    $scope.attr("data-media-rendered", "true");
                }
            },

            enumerable: false,
            writable: true
        },

        toggleDesktopDropdownTabs: {
            value: function() {
                if (this.tabSetWidth < this.tabsWidth) {
                    this.$overlayScope.addClass("dropdown-tabs");
                } else {
                    this.$overlayScope.removeClass("dropdown-tabs");
                }
            },

            enumerable: false,
            writable: true
        },

        bindVideoEvents: {
            value: function($scope, videoId) {
                $scope.on("click", function () {
                    Services("youtubeIframeApi").loadApi($scope.siblings(".player-store")[0], videoId, function (player){
                        // Hide pseudo play button
                        $scope.hide();
                        $scope.prev().hide();
                    });
                });
            },

            enumerable: false,
            writable: true
        }
    });

    return Gallery;
}();

return Gallery;
});
}).apply(window);/**!!<[ModuleGallery_com]!!**/
/**!![ModuleCopy_com]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_gallery"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, lambda=this.lambda, buffer = "        <li>\n            <div class=\"content\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.youTube : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.program(4, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "                <div class=\"description\">";
  stack1 = lambda((depth0 != null ? depth0.description : depth0), depth0);
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</div>\n            </div>\n        </li>\n";
},"2":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                <div class=\"video-wrapper\">\n                    <img title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" alt=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" data-media=\"https://img.youtube.com/vi/"
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "/0.jpg\" data-video=\"true\" data-render-video=\""
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "\">\n                    <a href=\"#\" class=\"video-link\"></a>\n                    <div class=\"player-store\"></div>\n                </div>\n";
},"4":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                <img title=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" alt=\""
    + escapeExpression(lambda((depth0 != null ? depth0.title : depth0), depth0))
    + "\" data-media=\""
    + escapeExpression(lambda((depth0 != null ? depth0.image : depth0), depth0))
    + "\">\n";
},"6":function(depth0,helpers,partials,data) {
  var stack1, buffer = "                <li>\n";
  stack1 = helpers.each.call(depth0, depth0, {"name":"each","hash":{},"fn":this.program(7, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                </li>\n";
},"7":function(depth0,helpers,partials,data) {
  var stack1, buffer = "                    <a href=\"javascript:\">\n";
  stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.youTube : depth0), {"name":"if","hash":{},"fn":this.program(8, data),"inverse":this.program(10, data),"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "                    </a>\n";
},"8":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        <img data-media=\"https://img.youtube.com/vi/"
    + escapeExpression(lambda((depth0 != null ? depth0.youTube : depth0), depth0))
    + "/0.jpg\" data-video=\"true\">\n";
},"10":function(depth0,helpers,partials,data) {
  var lambda=this.lambda, escapeExpression=this.escapeExpression;
  return "                        <img data-media=\""
    + escapeExpression(lambda((depth0 != null ? depth0.image : depth0), depth0))
    + "\">\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "<div class=\"gallery\" data-gallery-d=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\">\n    <div class=\"gallery-details res-1280-cols-10 res-1024-cols-10 res-752-cols-10\">\n        <h2 class=\"title\">"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</h2>\n        <div class=\"description\">";
  stack1 = ((helper = (helper = helpers.description || (depth0 != null ? depth0.description : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"description","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  buffer += "</div>\n    </div>\n    <ul class=\"slides\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "    </ul>\n    <div class=\"thumbnails\">\n        <div class=\"slides-wrapper\">\n            <ul class=\"slides\">\n";
  stack1 = ((helpers.grouped_each || (depth0 && depth0.grouped_each) || helperMissing).call(depth0, 5, (depth0 != null ? depth0.items : depth0), {"name":"grouped_each","hash":{},"fn":this.program(6, data),"inverse":this.noop,"data":data}));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "            </ul>\n        </div>\n    </div>\n    <div class=\"info\"></div>\n</div>";
},"useData":true});
this["templates"]["_info"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "<div class=\"info\">\n    <span class=\"current\">"
    + escapeExpression(((helper = (helper = helpers.current || (depth0 != null ? depth0.current : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"current","hash":{},"data":data}) : helper)))
    + "</span>\n    <span class=\"total\">of "
    + escapeExpression(((helper = (helper = helpers.total || (depth0 != null ? depth0.total : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"total","hash":{},"data":data}) : helper)))
    + "</span>\n</div>";
},"useData":true});
this["templates"]["_tableNotification"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  return "<div class=\"test\">\n    <span class=\"test2\"></span>\n    <span class=\"test3\"></span>\n</div>";
  },"useData":true});
this["templates"]["_tabs"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + " data-gallery-id=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\"><a title=\""
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "\" href=\"#\">"
    + escapeExpression(((helper = (helper = helpers.title || (depth0 != null ? depth0.title : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"title","hash":{},"data":data}) : helper)))
    + "</a></li>\n";
},"2":function(depth0,helpers,partials,data) {
  return "class=\"selected\"";
  },"4":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "    <li ";
  stack1 = helpers['if'].call(depth0, (data && data.first), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += " data-gallery-id=\""
    + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
    + "\">";
  stack1 = ((helper = (helper = helpers.content || (depth0 != null ? depth0.content : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"content","hash":{},"data":data}) : helper));
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"tabs-select-wrapper\">\n	<a href=\"#\" class=\"tabs-select\" title=\"Open galleries select menu\"></a>\n</div>\n<ul class=\"helper-tabs level-1\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "</ul>\n<ul class=\"helper-tabs level-2\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.items : depth0), {"name":"each","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "</ul>";
},"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('ModuleCopy.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerModule("ModuleCopy", "com", function() {
function CopyModule() {
    this.$window = null;
    this.$body = null;

    this.templates = null;
    this.language = null;
    this.email = null;

    this.config = {
        scope: view.$
    };
    this.translations = {
        en: {
            a: "Close",
            b: "See details",
            c: "The page you are viewing contains large tables which will not present well on mobile.",
            d: "Email me link to this page.",
            e: "Email link to page.",
            f: "SEND",
            g: "Email Confirmation.",
            h: "An email has been sent to the address you entered. Please check your spam folder if it does not arrive promptly.",
            i: "RESEND"
        },
        ja: {
            a: "閉じる",
            b: "詳細を見る",
            c: "このページの表示には時間がかかる可能性があります。",
            d: "このページのURLをメールで送る",
            e: "URLをメールで送信する",
            f: "送信",
            g: "メールアドレスを確認する",
            h: "メールが送信されました。メールが届かない場合は、迷惑メールの設定をご確認ください。",
            i: "再送信"
        }
    };

    setTimeout(function() {
        this.init.call(this, Services("pagetools"));
    }.bind(this));
}

CopyModule.prototype = {
    construct: CopyModule,
    init: function(pagetools) {
        var self = this;

        new (Helpers("gallery-overlay"))(this.config);

        this.$window = pagetools.window._element;
        this.$body = pagetools.body._element;

        this.templates = {
            _tableNotification: Services("templateService").templates("ModuleCopy._tableNotification")
        };

        if(this.$body.find("table").length > 0){
            this.myscroll();
            this.checkLanguage();
            this.manageDimensions();
            this.bindEvents();
            this.$window.resize(function(){
                self.manageDimensions();
            });
        }
    },

    myscroll: function(){
        (function (window, document, Math) {
            !function(t,i,s){
                function e(t,s){
                    this.wrapper="string"==typeof t?i.querySelector(t):t,this.scroller=this.wrapper.children[0],this.scrollerStyle=this.scroller.style,this.options={startX: 0,startY: 0,scrollY: !0,directionLockThreshold: 5,momentum: !0,bounce: !0,bounceTime: 600,bounceEasing: "",preventDefault: !0,preventDefaultException: {tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/},HWCompositing: !0,useTransition: !0,useTransform: !0};for(var e in s)this.options[e]=s[e];this.translateZ=this.options.HWCompositing&&o.hasPerspective?" translateZ(0)":"",this.options.useTransition=o.hasTransition&&this.options.useTransition,this.options.useTransform=o.hasTransform&&this.options.useTransform,this.options.eventPassthrough=this.options.eventPassthrough===!0?"vertical":this.options.eventPassthrough,this.options.preventDefault=!this.options.eventPassthrough&&this.options.preventDefault,this.options.scrollY="vertical"==this.options.eventPassthrough?!1:this.options.scrollY,this.options.scrollX="horizontal"==this.options.eventPassthrough?!1:this.options.scrollX,this.options.freeScroll=this.options.freeScroll&&!this.options.eventPassthrough,this.options.directionLockThreshold=this.options.eventPassthrough?0:this.options.directionLockThreshold,this.options.bounceEasing="string"==typeof this.options.bounceEasing?o.ease[this.options.bounceEasing]||o.ease.circular:this.options.bounceEasing,this.options.resizePolling=void 0===this.options.resizePolling?60:this.options.resizePolling,this.options.tap===!0&&(this.options.tap="tap"),this.x=0,this.y=0,this.directionX=0,this.directionY=0,this._events={},this._init(),this.refresh(),this.scrollTo(this.options.startX,this.options.startY),this.enable();
                }var n=t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.oRequestAnimationFrame||t.msRequestAnimationFrame||function(i){
                    t.setTimeout(i,1000/60);
                },o=function(){
                    function e(t){
                        return r===!1?!1:""===r?t:r+t.charAt(0).toUpperCase()+t.substr(1);
                    }var n={},o=i.createElement("div").style,r=function(){
                        for(var t,i=["t","webkitT","MozT","msT","OT"],s=0,e=i.length;e>s;s++)if(t=i[s]+"ransform",t in o)return i[s].substr(0,i[s].length-1);return!1;
                    }();n.getTime=Date.now||function(){
                        return(new Date).getTime();
                    },n.extend=function(t,i){
                        for(var s in i)t[s]=i[s];
                    },n.addEvent=function(t,i,s,e){
                        t.addEventListener(i,s,!!e);
                    },n.removeEvent=function(t,i,s,e){
                        t.removeEventListener(i,s,!!e);
                    },n.prefixPointerEvent=function(i){
                        return t.MSPointerEvent?"MSPointer"+i.charAt(9).toUpperCase()+i.substr(10):i;
                    },n.momentum=function(t,i,e,n,o,r){
                        var h,a,l=t-i,c=s.abs(l)/e;return (r=void 0===r?0.0006:r, h=t+c*c/(2*r)*(0>l?-1:1), a=c/r, n>h?(h=o?n-o/2.5*(c/8):n,l=s.abs(h-t),a=l/c):h>0&&(h=o?o/2.5*(c/8):0,l=s.abs(t)+h,a=l/c), {destination: s.round(h),duration: a});
                    };var h=e("transform");return (n.extend(n,{hasTransform: h!==!1,hasPerspective: e("perspective")in o,hasTouch: "ontouchstart"in t,hasPointer: t.PointerEvent||t.MSPointerEvent,hasTransition: e("transition")in o}), n.isBadAndroid=/Android /.test(t.navigator.appVersion)&&!/Chrome\/\d/.test(t.navigator.appVersion), n.extend(n.style={},{transform: h,transitionTimingFunction: e("transitionTimingFunction"),transitionDuration: e("transitionDuration"),transitionDelay: e("transitionDelay"),transformOrigin: e("transformOrigin")}), n.hasClass=function(t,i){
                        var s=new RegExp("(^|\\s)"+i+"(\\s|$)");return s.test(t.className);
                    }, n.addClass=function(t,i){
                        if(!n.hasClass(t,i)){
                            var s=t.className.split(" ");s.push(i),t.className=s.join(" ");
                        }
                    }, n.removeClass=function(t,i){
                        if(n.hasClass(t,i)){
                            var s=new RegExp("(^|\\s)"+i+"(\\s|$)","g");t.className=t.className.replace(s," ");
                        }
                    }, n.offset=function(t){
                        for(var i=-t.offsetLeft,s=-t.offsetTop;t=t.offsetParent;)i-=t.offsetLeft,s-=t.offsetTop;return{left: i,top: s}
                    }, n.preventDefaultException=function(t,i){
                        for(var s in i)if(i[s].test(t[s]))return!0;return!1;
                    }, n.extend(n.eventType={},{touchstart: 1,touchmove: 1,touchend: 1,mousedown: 2,mousemove: 2,mouseup: 2,pointerdown: 3,pointermove: 3,pointerup: 3,MSPointerDown: 3,MSPointerMove: 3,MSPointerUp: 3}), n.extend(n.ease={},{quadratic: {style: "cubic-bezier(0.25, 0.46, 0.45, 0.94)",fn: function(t){
                        return t*(2-t);
                    }},circular: {style: "cubic-bezier(0.1, 0.57, 0.1, 1)",fn: function(t){
                        return s.sqrt(1- --t*t);
                    }},back: {style: "cubic-bezier(0.175, 0.885, 0.32, 1.275)",fn: function(t){
                        var i=4;return(t-=1)*t*((i+1)*t+i)+1;
                    }},bounce: {style: "",fn: function(t){
                        return(t/=1)<1/2.75?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+0.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+0.9375:7.5625*(t-=2.625/2.75)*t+0.984375;
                    }},elastic: {style: "",fn: function(t){
                        var i=0.22,e=0.4;return 0===t?0:1==t?1:e*s.pow(2,-10*t)*s.sin(2*(t-i/4)*s.PI/i)+1;
                    }}}), n.tap=function(t,s){
                        var e=i.createEvent("Event");e.initEvent(s,!0,!0),e.pageX=t.pageX,e.pageY=t.pageY,t.target.dispatchEvent(e);
                    }, n.click=function(t){
                        var s,e=t.target;/(SELECT|INPUT|TEXTAREA)/i.test(e.tagName)||(s=i.createEvent("MouseEvents"),s.initMouseEvent("click",!0,!0,t.view,1,e.screenX,e.screenY,e.clientX,e.clientY,t.ctrlKey,t.altKey,t.shiftKey,t.metaKey,0,null),s._constructed=!0,e.dispatchEvent(s));
                    }, n);
                }();e.prototype={version: "5.1.3",_init: function(){
                    this._initEvents();
                },destroy: function(){
                    this._initEvents(!0),this._execEvent("destroy");
                },_transitionEnd: function(t){
                    t.target==this.scroller&&this.isInTransition&&(this._transitionTime(),this.resetPosition(this.options.bounceTime)||(this.isInTransition=!1,this._execEvent("scrollEnd")));
                },_start: function(t){
                    if(!(1!=o.eventType[t.type]&&0!==t.button||!this.enabled||this.initiated&&o.eventType[t.type]!==this.initiated)){
                        !this.options.preventDefault||o.isBadAndroid||o.preventDefaultException(t.target,this.options.preventDefaultException)||t.preventDefault();var i,e=t.touches?t.touches[0]:t;this.initiated=o.eventType[t.type],this.moved=!1,this.distX=0,this.distY=0,this.directionX=0,this.directionY=0,this.directionLocked=0,this._transitionTime(),this.startTime=o.getTime(),this.options.useTransition&&this.isInTransition?(this.isInTransition=!1,i=this.getComputedPosition(),this._translate(s.round(i.x),s.round(i.y)),this._execEvent("scrollEnd")):!this.options.useTransition&&this.isAnimating&&(this.isAnimating=!1,this._execEvent("scrollEnd")),this.startX=this.x,this.startY=this.y,this.absStartX=this.x,this.absStartY=this.y,this.pointX=e.pageX,this.pointY=e.pageY,this._execEvent("beforeScrollStart");
                    }
                },_move: function(t){
                    if(this.enabled&&o.eventType[t.type]===this.initiated){
                        this.options.preventDefault&&t.preventDefault();var i,e,n,r,h=t.touches?t.touches[0]:t,a=h.pageX-this.pointX,l=h.pageY-this.pointY,c=o.getTime();if(this.pointX=h.pageX,this.pointY=h.pageY,this.distX+=a,this.distY+=l,n=s.abs(this.distX),r=s.abs(this.distY),!(c-this.endTime>300&&10>n&&10>r)){
                            if(this.directionLocked||this.options.freeScroll||(this.directionLocked=n>r+this.options.directionLockThreshold?"h":r>=n+this.options.directionLockThreshold?"v":"n"),"h"==this.directionLocked){
                                if("vertical"==this.options.eventPassthrough)t.preventDefault();else if("horizontal"==this.options.eventPassthrough)return void(this.initiated=!1);l=0;
                            }else if("v"==this.directionLocked){
                                if("horizontal"==this.options.eventPassthrough)t.preventDefault();else if("vertical"==this.options.eventPassthrough)return void(this.initiated=!1);a=0;
                            }a=this.hasHorizontalScroll?a:0,l=this.hasVerticalScroll?l:0,i=this.x+a,e=this.y+l,(i>0||i<this.maxScrollX)&&(i=this.options.bounce?this.x+a/3:i>0?0:this.maxScrollX),(e>0||e<this.maxScrollY)&&(e=this.options.bounce?this.y+l/3:e>0?0:this.maxScrollY),this.directionX=a>0?-1:0>a?1:0,this.directionY=l>0?-1:0>l?1:0,this.moved||this._execEvent("scrollStart"),this.moved=!0,this._translate(i,e),c-this.startTime>300&&(this.startTime=c,this.startX=this.x,this.startY=this.y);
                        }
                    }
                },_end: function(t){
                    if(this.enabled&&o.eventType[t.type]===this.initiated){
                        this.options.preventDefault&&!o.preventDefaultException(t.target,this.options.preventDefaultException)&&t.preventDefault();var i,e,n=(t.changedTouches?t.changedTouches[0]:t,o.getTime()-this.startTime),r=s.round(this.x),h=s.round(this.y),a=s.abs(r-this.startX),l=s.abs(h-this.startY),c=0,p="";if(this.isInTransition=0,this.initiated=0,this.endTime=o.getTime(),!this.resetPosition(this.options.bounceTime))return (this.scrollTo(r,h), this.moved?this._events.flick&&200>n&&100>a&&100>l?void this._execEvent("flick"):(this.options.momentum&&300>n&&(i=this.hasHorizontalScroll?o.momentum(this.x,this.startX,n,this.maxScrollX,this.options.bounce?this.wrapperWidth:0,this.options.deceleration):{destination: r,duration: 0},e=this.hasVerticalScroll?o.momentum(this.y,this.startY,n,this.maxScrollY,this.options.bounce?this.wrapperHeight:0,this.options.deceleration):{destination: h,duration: 0},r=i.destination,h=e.destination,c=s.max(i.duration,e.duration),this.isInTransition=1),r!=this.x||h!=this.y?((r>0||r<this.maxScrollX||h>0||h<this.maxScrollY)&&(p=o.ease.quadratic),void this.scrollTo(r,h,c,p)):void this._execEvent("scrollEnd")):(this.options.tap&&o.tap(t,this.options.tap),this.options.click&&o.click(t),void this._execEvent("scrollCancel")));
                    }
                },_resize: function(){
                    var t=this;clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(function(){
                        t.refresh();
                    },this.options.resizePolling);
                },resetPosition: function(t){
                    var i=this.x,s=this.y;return (t=t||0, !this.hasHorizontalScroll||this.x>0?i=0:this.x<this.maxScrollX&&(i=this.maxScrollX), !this.hasVerticalScroll||this.y>0?s=0:this.y<this.maxScrollY&&(s=this.maxScrollY), i==this.x&&s==this.y?!1:(this.scrollTo(i,s,t,this.options.bounceEasing),!0));
                },disable: function(){
                    this.enabled=!1;
                },enable: function(){
                    this.enabled=!0;
                },refresh: function(){
                    this.wrapper.offsetHeight;this.wrapperWidth=this.wrapper.clientWidth,this.wrapperHeight=this.wrapper.clientHeight,this.scrollerWidth=this.scroller.offsetWidth,this.scrollerHeight=this.scroller.offsetHeight,this.maxScrollX=this.wrapperWidth-this.scrollerWidth,this.maxScrollY=this.wrapperHeight-this.scrollerHeight,this.hasHorizontalScroll=this.options.scrollX&&this.maxScrollX<0,this.hasVerticalScroll=this.options.scrollY&&this.maxScrollY<0,this.hasHorizontalScroll||(this.maxScrollX=0,this.scrollerWidth=this.wrapperWidth),this.hasVerticalScroll||(this.maxScrollY=0,this.scrollerHeight=this.wrapperHeight),this.endTime=0,this.directionX=0,this.directionY=0,this.wrapperOffset=o.offset(this.wrapper),this._execEvent("refresh"),this.resetPosition();
                },on: function(t,i){
                    this._events[t]||(this._events[t]=[]),this._events[t].push(i);
                },off: function(t,i){
                    if(this._events[t]){
                        var s=this._events[t].indexOf(i);s>-1&&this._events[t].splice(s,1);
                    }
                },_execEvent: function(t){
                    if(this._events[t]){
                        var i=0,s=this._events[t].length;if(s)for(;s>i;i++)this._events[t][i].apply(this,[].slice.call(arguments,1));
                    }
                },scrollBy: function(t,i,s,e){
                    t=this.x+t,i=this.y+i,s=s||0,this.scrollTo(t,i,s,e);
                },scrollTo: function(t,i,s,e){
                    e=e||o.ease.circular,this.isInTransition=this.options.useTransition&&s>0,!s||this.options.useTransition&&e.style?(this._transitionTimingFunction(e.style),this._transitionTime(s),this._translate(t,i)):this._animate(t,i,s,e.fn);
                },scrollToElement: function(t,i,e,n,r){
                    if(t=t.nodeType?t:this.scroller.querySelector(t)){
                        var h=o.offset(t);h.left-=this.wrapperOffset.left,h.top-=this.wrapperOffset.top,e===!0&&(e=s.round(t.offsetWidth/2-this.wrapper.offsetWidth/2)),n===!0&&(n=s.round(t.offsetHeight/2-this.wrapper.offsetHeight/2)),h.left-=e||0,h.top-=n||0,h.left=h.left>0?0:h.left<this.maxScrollX?this.maxScrollX:h.left,h.top=h.top>0?0:h.top<this.maxScrollY?this.maxScrollY:h.top,i=void 0===i||null===i||"auto"===i?s.max(s.abs(this.x-h.left),s.abs(this.y-h.top)):i,this.scrollTo(h.left,h.top,i,r);
                    }
                },_transitionTime: function(t){
                    t=t||0,this.scrollerStyle[o.style.transitionDuration]=t+"ms",!t&&o.isBadAndroid&&(this.scrollerStyle[o.style.transitionDuration]="0.001s");
                },_transitionTimingFunction: function(t){
                    this.scrollerStyle[o.style.transitionTimingFunction]=t;
                },_translate: function(t,i){
                    this.options.useTransform?this.scrollerStyle[o.style.transform]="translate("+t+"px,"+i+"px)"+this.translateZ:(t=s.round(t),i=s.round(i),this.scrollerStyle.left=t+"px",this.scrollerStyle.top=i+"px"),this.x=t,this.y=i;
                },_initEvents: function(i){
                    var s=i?o.removeEvent:o.addEvent,e=this.options.bindToWrapper?this.wrapper:t;s(t,"orientationchange",this),s(t,"resize",this),this.options.click&&s(this.wrapper,"click",this,!0),this.options.disableMouse||(s(this.wrapper,"mousedown",this),s(e,"mousemove",this),s(e,"mousecancel",this),s(e,"mouseup",this)),o.hasPointer&&!this.options.disablePointer&&(s(this.wrapper,o.prefixPointerEvent("pointerdown"),this),s(e,o.prefixPointerEvent("pointermove"),this),s(e,o.prefixPointerEvent("pointercancel"),this),s(e,o.prefixPointerEvent("pointerup"),this)),o.hasTouch&&!this.options.disableTouch&&(s(this.wrapper,"touchstart",this),s(e,"touchmove",this),s(e,"touchcancel",this),s(e,"touchend",this)),s(this.scroller,"transitionend",this),s(this.scroller,"webkitTransitionEnd",this),s(this.scroller,"oTransitionEnd",this),s(this.scroller,"MSTransitionEnd",this);
                },getComputedPosition: function(){
                    var i,s,e=t.getComputedStyle(this.scroller,null);return (this.options.useTransform?(e=e[o.style.transform].split(")")[0].split(", "),i=+(e[12]||e[4]),s=+(e[13]||e[5])):(i=+e.left.replace(/[^-\d.]/g,""),s=+e.top.replace(/[^-\d.]/g,"")), {x: i,y: s});
                },_animate: function(t,i,s,e){
                    function r(){
                        var u,f,d,m=o.getTime();return m>=p?(h.isAnimating=!1,h._translate(t,i),void(h.resetPosition(h.options.bounceTime)||h._execEvent("scrollEnd"))):(m=(m-c)/s,d=e(m),u=(t-a)*d+a,f=(i-l)*d+l,h._translate(u,f),void(h.isAnimating&&n(r)));
                    }var h=this,a=this.x,l=this.y,c=o.getTime(),p=c+s;this.isAnimating=!0,r();
                },handleEvent: function(t){
                    switch(t.type){case"touchstart":case"pointerdown":case"MSPointerDown":case"mousedown":this._start(t);break;case"touchmove":case"pointermove":case"MSPointerMove":case"mousemove":this._move(t);break;case"touchend":case"pointerup":case"MSPointerUp":case"mouseup":case"touchcancel":case"pointercancel":case"MSPointerCancel":case"mousecancel":this._end(t);break;case"orientationchange":case"resize":this._resize();break;case"transitionend":case"webkitTransitionEnd":case"oTransitionEnd":case"MSTransitionEnd":this._transitionEnd(t);break;case"wheel":case"DOMMouseScroll":case"mousewheel":this._wheel(t);break;case"keydown":this._key(t);break;case"click":t._constructed||(t.preventDefault(),t.stopPropagation())}
                }},e.utils=o,"undefined"!=typeof module&&module.exports?module.exports=e:t.IScroll=e;
            }(window,document,Math);
        })(this.$window.prevObject[0], this.$window.prevObject[0].document, this.$window.prevObject[0].Math);
    },

    checkLanguage: function(){
        this.language = this.$body.hasClass("en") ? "en" : "ja";
    },

    getScreenWidth: function(){
        return this.$window.width();
    },

    manageDimensions: function(){
        // hide tables and show table module elements
        if(this.getScreenWidth() < 768){
            // this.createEmailInfo();
            this.createTable();
            var tables = this.$body.find("table");

            tables.each(function(index){
                if(!$(this).hasClass("show-mobile"))
                    $(this).addClass("hiddenTable");
            });

            this.bindEvents();
        }
        // hide table module elements and show desktop table
        else{
            view.$.find(".hiddenTable").removeClass("hiddenTable");
            view.$.find(".box").remove();
            this.$body.find(".tb-container").remove();
            this.$body.find(".email-info").remove();
            this.$body.find(".popup-email-container").remove();
        }
    },

    createEmailInfo: function(){
        if(!this.$body.find(".email-info").length){
            var emailInfo = $("<div class=\"email-info\">"+
                                "<p>"+this.translations[this.language].c+"</p>"+
                                "<div class=\"email-button\">"+
                                    "<span>"+this.translations[this.language].d+"</span>"+
                                "</div>"+
                            "</div>");
            this.$body.find(".main-content").prepend(emailInfo);
        }
    },

    createTable: function() {
        if(!this.$body.find(".tb-container").length){
            var tables =  this.$body.find("table");
            var self = this;

            tables.each(function(index) {
                if(!$(this).hasClass("show-mobile")){
                    //copy each table and append them to the module in containers and keep hidden
                    var container = $("<div id=\"iscroll-wrapper-"+index+"\" class=\"iscroll-wrapper tb-container hiddenElement tb-container-"+index+"\">" +
                                        "<div id=\"scroller\">" +
                                        "</div>"+
                                        "<div class=\"close-window\">"+
                                            "<div class=\"close-table-full\"> " +
                                                "<span class=\"close-text\"> "+ self.translations[self.language].a +" </span>" +
                                                "<span class=\"cross-icon\"></span>"+
                                            "</div>"+
                                        "</div>"+
                                    "</div>");
                    self.$body.prepend(container);
                    self.$body.find(".tb-container-"+index).find("#scroller").append($(this).clone());
                    //for each table create box with button to show full screen table, keep hidden
                    var triggerBox = $("<div class=\"box\" data-box=\""+index+"\">"+
                                            "<span class=\"graph-icon\"></span>"+
                                            "<div class=\"showTable\">"+
                                                "<span class=\"see-table\">"+self.translations[self.language].b+"</span>"+
                                                "<span class=\"right-arrow-icon\"></span>"+
                                            "</div>"+
                                        "</div>");
                    triggerBox.insertBefore($(this));
                }
            });
        }
    },

    bindEvents: function() {
        var self = this;
        self.$body.find(".showTable").off().on("click", this.onOpen.bind(this));
        self.$body.find(".close-window").off().on("click", function(){
            self.onClose($(this));
        });
        self.$body.find(".email-button").on("click", this.openEmail.bind(this));
        self.$body.find(".close-email").on("click", this.closeEmail.bind(this));
        self.$body.find(".sendEmail").on("click", this.collectEmail.bind(this));
        self.$body.find(".resendEmail").on("click", this.resendEmail.bind(this));
    },

    // grab clients email
    collectEmail: function(eventObject){
        this.email = this.$body.find(".popup-email-first .email-page-link").val();
        this.sendEmail(eventObject);
    },

    validateEmail: function(){
        var regEx = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        var validation = this.email.match(regEx);
        return validation;
    },

    sendEmail: function(eventObject){
        if(!this.validateEmail()) return;
        this.openMailClient(eventObject);
        this.$body.find(".popup-email-first").addClass("hiddenElement");
        this.$body.find(".popup-email-confirmation").removeClass("hiddenElement");
    },

    resendEmail: function(eventObject){
        this.$body.find(".popup-email-first").removeClass("hiddenElement");
        this.$body.find(".popup-email-confirmation").addClass("hiddenElement");
        this.$body.find(".popup-email-first .email-page-link").val(this.email);
    },

    //open default mail client
    openMailClient: function(eventObject){
        var link = this.$window.prevObject[0].document.location.href;
        var target = eventObject.delegateTarget;
        var ahref = ($(target).next());
        ahref.attr("href", "mailto:"+this.email+"?subject=Your link from Mazda.com&body="+link);
        ahref[0].click();
    },

    // create and open email popup
    openEmail: function(){
        if(!this.$body.find(".popup-email-container").length){
            var overlay = $("<div class=\"popup-email-container\">"+
                                "<div class=\"popup-email popup-email-first\">"+
                                    "<div class=\"close-email\">"+
                                        "<span>"+this.translations[this.language].a+"</span>"+
                                        "<span class=\"icon\"></span>"+
                                    "</div>"+
                                    "<div class=\"notification\">"+
                                        "<span class=\"envelope-icon\"></span>"+
                                        "<span>"+this.translations[this.language].e+"</span>"+
                                    "</div>"+
                                    "<form>"+
                                        "<input type=\"email\" name=\"email-page-link\" placeholder=\"example@domain.com\" class=\"email-page-link\" onfocus=\"return false;\">"+
                                    "</form>"+
                                    "<div class=\"emailButton sendEmail\"><span>"+this.translations[this.language].f+"</span><span class=\"right-arrow-icon\"></span></div>"+
                                    "<a href=\"\"></a>"+
                                "</div>"+

                                "<div class=\"popup-email popup-email-confirmation hiddenElement\">"+
                                    "<div class=\"close-email\">"+
                                        "<span>"+this.translations[this.language].a+"</span>"+
                                        "<span class=\"icon\">X</span>"+
                                    "</div>"+
                                    "<div class=\"notification\">"+
                                        "<span class=\"envelope-icon\"></span>"+
                                        "<span>"+this.translations[this.language].g+"</span>"+
                                    "</div>"+
                                    "<p>"+this.translations[this.language].h+"</p>"+
                                    "<div class=\"emailButton resendEmail\"><span>"+this.translations[this.language].i+"</span><span class=\"right-arrow-icon\"></span></div>"+
                                    "<a href=\"\"></a>"+
                                "</div>"+
                            "</div>");
            this.$body.prepend(overlay);
            this.bindEvents();
        }
        else{
            this.$body.find(".popup-email-container").removeClass("hiddenElement");
        }
    },

    // close email-popup
    closeEmail: function(){
        this.$body.find(".popup-email-container").addClass("hiddenElement");
        this.$body.find(".popup-email-first").removeClass("hiddenElement");
        this.$body.find(".popup-email-confirmation").addClass("hiddenElement");
    },

    // open full screen table
    onOpen: function(eventObject) {
        var self = this;
        var target = eventObject.delegateTarget;
        var boxID = $(target).closest(".box").data("box");
        this.$body.find(".tb-container-"+boxID).removeClass("hiddenElement");

        var myScroll;

        (this.$body, this.$body.find(".main-content")).css({
            position: "fixed",
            "z-index": "-1"
        });

        var IScroll = this.$window.prevObject[0].IScroll;
        myScroll = new IScroll("#iscroll-wrapper-"+boxID, {
            mouseWheel: true,
            freeScroll: true,
            scrollbars: true,
            scrollX: true,
            scrollY: true,
            click: true,
            tap: true
        });

        this.$body.prepend("<div id=\"iscroll-backlay\"></div>");

        setTimeout(function() {
            myScroll.refresh();
        }, 50);
    },

    // close full screen table
    onClose: function(el) {
        el.closest(".tb-container").addClass("hiddenElement");
        (this.$body, this.$body.find(".main-content")).css({
           position: "relative",
           "z-index": "initial"
       });
        this.$body.find("#iscroll-backlay").remove();
    }


};

return CopyModule;


/*ie8Message = this.Templates._ie8({
title: 'ご使',
details: '以下の'
});*/
});
}).apply(window);/**!!<[ModuleCopy_com]!!**/
/**!![ModuleDistributorList_com]>!!**/
(function(){
registerModule("ModuleDistributorList", "com", function() {
/*
 *	jQuery dotdotdot 1.6.16
 *
 *	Copyright (c) Fred Heusschen
 *	www.frebsite.nl
 *
 *	Plugin website:
 *	dotdotdot.frebsite.nl
 *
 *	Dual licensed under the MIT and GPL licenses.
 *	http://en.wikipedia.org/wiki/MIT_License
 *	http://en.wikipedia.org/wiki/GNU_General_Public_License
 */
!function(t,e){
 function n(t,e,n){
  var r=t.children(),o=!1;t.empty();for(var i=0,d=r.length;d>i;i++){
   var l=r.eq(i);if(t.append(l),n&&t.append(n),a(t,e)){
    l.remove(),o=!0;break;
   }n&&n.detach();
  }return o;
 }function r(e,n,i,d,l){
  var s=!1,c="table, thead, tbody, tfoot, tr, col, colgroup, object, embed, param, ol, ul, dl, blockquote, select, optgroup, option, textarea, script, style",u="script, .dotdotdot-keep";return (e.contents().detach().each(function(){
   var f=this,h=t(f);if("undefined"==typeof f||3==f.nodeType&&0==t.trim(f.data).length)return!0;if(h.is(u))e.append(h);else{
    if(s)return!0;e.append(h),l&&e[e.is(c)?"after":"append"](l),a(i,d)&&(s=3==f.nodeType?o(h,n,i,d,l):r(h,n,i,d,l),s||(h.detach(),s=!0)),s||l&&l.detach();
   }
  }), s);
 }function o(e,n,r,o,d){
  var c=e[0];if(!c)return!1;var f=s(c),h=-1!==f.indexOf(" ")?" ":"　",p="letter"==o.wrap?"":h,g=f.split(p),v=-1,w=-1,b=0,y=g.length-1;for(o.fallbackToLetter&&0==b&&0==y&&(p="",g=f.split(p),y=g.length-1);y>=b&&(0!=b||0!=y);){
   var m=Math.floor((b+y)/2);if(m==w)break;w=m,l(c,g.slice(0,w+1).join(p)+o.ellipsis),a(r,o)?(y=w,o.fallbackToLetter&&0==b&&0==y&&(p="",g=g[0].split(p),v=-1,w=-1,b=0,y=g.length-1)):(v=w,b=w);
  }if(-1==v||1==g.length&&0==g[0].length){
   var x=e.parent();e.detach();var T=d&&d.closest(x).length?d.length:0;x.contents().length>T?c=u(x.contents().eq(-1-T),n):(c=u(x,n,!0),T||x.detach()),c&&(f=i(s(c),o),l(c,f),T&&d&&t(c).parent().append(d));
  }else f=i(g.slice(0,v+1).join(p),o),l(c,f);return!0;
 }function a(t,e){
  return t.innerHeight()>e.maxHeight;
 }function i(e,n){
  for(;t.inArray(e.slice(-1),n.lastCharacter.remove)>-1;)e=e.slice(0,-1);return (t.inArray(e.slice(-1),n.lastCharacter.noEllipsis)<0&&(e+=n.ellipsis), e);
 }function d(t){
  return{width: t.innerWidth(),height: t.innerHeight()}
 }function l(t,e){
  t.innerText?t.innerText=e:t.nodeValue?t.nodeValue=e:t.textContent&&(t.textContent=e);
 }function s(t){
  return t.innerText?t.innerText:t.nodeValue?t.nodeValue:t.textContent?t.textContent:"";
 }function c(t){
  do t=t.previousSibling;while(t&&1!==t.nodeType&&3!==t.nodeType);return t;
 }function u(e,n,r){
  var o,a=e&&e[0];if(a){
   if(!r){
    if(3===a.nodeType)return a;if(t.trim(e.text()))return u(e.contents().last(),n);
   }for(o=c(a);!o;){
    if(e=e.parent(),e.is(n)||!e.length)return!1;o=c(e[0]);
   }if(o)return u(t(o),n);
  }return!1;
 }function f(e,n){
  return e?"string"==typeof e?(e=t(e,n),e.length?e:!1):e.jquery?e:!1:!1;
 }function h(t){
  for(var e=t.innerHeight(),n=["paddingTop","paddingBottom"],r=0,o=n.length;o>r;r++){
   var a=parseInt(t.css(n[r]),10);isNaN(a)&&(a=0),e-=a;
  }return e;
 }if(!t.fn.dotdotdot){
  t.fn.dotdotdot=function(e){
   if(0==this.length)return (t.fn.dotdotdot.debug("No element found for \""+this.selector+"\"."), this);if(this.length>1)return this.each(function(){
    t(this).dotdotdot(e);
   });var o=this;o.data("dotdotdot")&&o.trigger("destroy.dot"),o.data("dotdotdot-style",o.attr("style")||""),o.css("word-wrap","break-word"),"nowrap"===o.css("white-space")&&o.css("white-space","normal"),o.bind_events=function(){
    return (o.bind("update.dot",function(e,d){
     e.preventDefault(),e.stopPropagation(),l.maxHeight="number"==typeof l.height?l.height:h(o),l.maxHeight+=l.tolerance,"undefined"!=typeof d&&(("string"==typeof d||d instanceof HTMLElement)&&(d=t("<div />").append(d).contents()),d instanceof t&&(i=d)),g=o.wrapInner("<div class=\"dotdotdot\" />").children(),g.contents().detach().end().append(i.clone(!0)).find("br").replaceWith("  <br />  ").end().css({height: "auto",width: "auto",border: "none",padding: 0,margin: 0});var c=!1,u=!1;return (s.afterElement&&(c=s.afterElement.clone(!0),c.show(),s.afterElement.detach()), a(g,l)&&(u="children"==l.wrap?n(g,l,c):r(g,o,g,l,c)), g.replaceWith(g.contents()), g=null, t.isFunction(l.callback)&&l.callback.call(o[0],u,i), s.isTruncated=u, u);
    }).bind("isTruncated.dot",function(t,e){
     return (t.preventDefault(), t.stopPropagation(), "function"==typeof e&&e.call(o[0],s.isTruncated), s.isTruncated);
    }).bind("originalContent.dot",function(t,e){
     return (t.preventDefault(), t.stopPropagation(), "function"==typeof e&&e.call(o[0],i), i);
    }).bind("destroy.dot",function(t){
     t.preventDefault(),t.stopPropagation(),o.unwatch().unbind_events().contents().detach().end().append(i).attr("style",o.data("dotdotdot-style")||"").data("dotdotdot",!1);
    }), o);
   },o.unbind_events=function(){
    return (o.unbind(".dot"), o);
   },o.watch=function(){
    if(o.unwatch(),"window"==l.watch){
     var e=t(window),n=e.width(),r=e.height();e.bind("resize.dot"+s.dotId,function(){
      n==e.width()&&r==e.height()&&l.windowResizeFix||(n=e.width(),r=e.height(),u&&clearInterval(u),u=setTimeout(function(){
       o.trigger("update.dot");
      },100));
     });
    }else c=d(o),u=setInterval(function(){
     if(o.is(":visible")){
      var t=d(o);(c.width!=t.width||c.height!=t.height)&&(o.trigger("update.dot"),c=t);
     }
    },500);return o;
   },o.unwatch=function(){
    return (t(window).unbind("resize.dot"+s.dotId), u&&clearInterval(u), o);
   };var i=o.contents(),l=t.extend(!0,{},t.fn.dotdotdot.defaults,e),s={},c={},u=null,g=null;return (l.lastCharacter.remove instanceof Array||(l.lastCharacter.remove=t.fn.dotdotdot.defaultArrays.lastCharacter.remove), l.lastCharacter.noEllipsis instanceof Array||(l.lastCharacter.noEllipsis=t.fn.dotdotdot.defaultArrays.lastCharacter.noEllipsis), s.afterElement=f(l.after,o), s.isTruncated=!1, s.dotId=p++, o.data("dotdotdot",!0).bind_events().trigger("update.dot"), l.watch&&o.watch(), o);
  },t.fn.dotdotdot.defaults={ellipsis: "... ",wrap: "word",fallbackToLetter: !0,lastCharacter: {},tolerance: 0,callback: null,after: null,height: null,watch: !1,windowResizeFix: !0},t.fn.dotdotdot.defaultArrays={lastCharacter: {remove: [" ","　",",",";",".","!","?"],noEllipsis: []}},t.fn.dotdotdot.debug=function(){};var p=1,g=t.fn.html;t.fn.html=function(n){
   return n!=e&&!t.isFunction(n)&&this.data("dotdotdot")?this.trigger("update",[n]):g.apply(this,arguments);
  };var v=t.fn.text;t.fn.text=function(n){
   return n!=e&&!t.isFunction(n)&&this.data("dotdotdot")?(n=t("<div />").text(n).html(),this.trigger("update",[n])):v.apply(this,arguments);
  }
 }
}(jQuery);
var dom = parent;

function DistributorList(){
    this.win = null;
    this.dekstop = null;
    this.currentView = null;
    this.region = null;

    setTimeout(function() {
        this.init.call(this, Services("pagetools"));
    }.bind(this));
}

DistributorList.prototype = {

    construct: DistributorList,

    init: function(pagetools){
        var self = this;
        this.win = pagetools.window._element;
        this.checkDimension();

        this.win.resize(function(event){
            self.checkDimension();
        });
    },

    checkDimension: function(){
        this.desktop = (this.win.width() < 750) ? false : true;
        if(this.currentView != this.desktop){
            this.currentView = this.desktop;
            this.createView();
            this.preselection();
            this.bindEvents();
        }
    },

    createView: function(){
        this.desktop ? this.createDesktopView() : this.createMobileView();
    },

    createDesktopView: function(){
        view.$.find("ul.tabs label").each(function(i){
            var continent = $(this).next();

            view.$.find("ul.continents").append(continent);
        });
        $("#heading").css({display: "block"});
    },

    createMobileView: function(){
        view.$.find("ul.tabs li").each(function(i){
            var continent = $(this).attr("data-tab");
            var countryList = $(".continents").find("#"+continent);
            $(this).append(countryList);
        });
        $("#heading").css({display: "none"});
    },

    getParameterByName: function(name){
        name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
        var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
        var results = regex.exec(this.win[0].location.href);
        return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
    },

    categoryExist: function(){
        var CookieService = Services("cookies");

        if (CookieService.isCookieSet("MazdaNearYou-continent")){
            this.region = CookieService.getCookie("MazdaNearYou-continent");
        }
        return ($(".tabs").find("[data-tab='"+this.region+"']").length > 0) ? true : false;
        /*            var region = this.getParameterByName('region');         
                    return ($('.tabs').find("[data-tab='"+region+"']").length > 0) ? true : false;  */;
    },

    preselection: function(){
        if(this.categoryExist()){
            this.preselectFromQuery();
        }
        else{
            this.desktop ? this.setDefaultStateDesktop() : this.setDefaultStateMobile();
        }
    },

    preselectFromQuery: function(){
        //var region = this.getParameterByName('region');
        if(this.desktop){
            this.resetDesktop();
            $("ul.tabs").find("[data-tab='"+this.region+"']").addClass("selected");
            $(".continents .continent").addClass("hidden");
            $(".continents").find("#"+this.region).removeClass("hidden");
        }
        else{
            $("li.continent").addClass("hidden");
            $("#"+this.region).removeClass("hidden");
            $(".tabs label").removeClass("down-arrow");
            $("#"+this.region).prev().toggleClass("down-arrow");
            $("#"+this.region).find("li.address").each(function(){
                var self = this;
                setTimeout(function(){
                    $(self).dotdotdot({
                        ellipsis: "..."
                    });
                }, 5);
            });
        }


        /*            var region = this.getParameterByName('region');
                    if(this.desktop){
                        this.resetDesktop();
                        $('ul.tabs').find("[data-tab='"+region+"']").addClass('selected');
                        $('.continents .continent').addClass('hidden');
                        $('.continents').find('#'+region).removeClass('hidden');
                    }
                    else{
                        $('li.continent').addClass('hidden');
                        $('#'+region).removeClass('hidden');
                        $('.tabs label').removeClass('down-arrow');
                        $('#'+region).prev().toggleClass('down-arrow');
                        $('#'+region).find("li.address").each(function(){
                            var self = this;
                            setTimeout(function(){
                               
                                $(self).dotdotdot({
                                    ellipsis    : '...'
                                });    
                            }, 5);
         
                        });           
                    } */;
    },

    setDefaultStateDesktop: function(){
        this.resetDesktop();
        $("ul.tabs").find("[data-tab='asia-pacific']").addClass("selected");
        $(".continents #asia-pacific").removeClass("hidden");
    },

    resetDesktop: function(){
        $(".country .address").trigger("destroy");
        $("ul.tabs li").removeClass("selected");
        $(".continents .continent").addClass("hidden");
    },

    setDefaultStateMobile: function(){
        $(".tabs li").removeClass("selected");
        $(".tabs .continent").addClass("hidden");
        $(".tabs label").removeClass("down-arrow");
        $(".tabs .country").addClass("limited");
        $(".tabs .address").removeClass("fullAddress");
    },

    bindEvents: function(){
        var self = this;
        $(".tabs label").off().on("click", function(){
            var continent = $(this).closest("li").attr("data-tab");
            if(self.desktop){
                self.selectTabDesktop(continent, $(this));
            } 
            else{
                $(this).next().toggleClass("hidden");
                $(this).toggleClass("down-arrow");
                $(this).closest(".tabs").find("li.address").dotdotdot({
                    ellipsis: "..."
                });
            }
        });

        if(!self.desktop){
            $(".reveal-button").off().on("click", function(){
                var address = $(this).closest(".country").find("li.address");
                address.toggleClass("fullAddress");
                if(address.hasClass("fullAddress")){
                    address.trigger("originalContent", function(content){
                        address.html($(content.context).html());
                    });
                    address.trigger("destroy");
                }else{
                    setTimeout(function(){
                        address.dotdotdot({
                            ellipsis: "..."
                        });
                    }, 50);
                }

                $(this).closest(".country").toggleClass("limited");
            });
        }
    },

    selectTabDesktop: function(continent, label){
        $("ul.tabs li").removeClass("selected");
        label.closest("li").addClass("selected");
        $("ul.continents .continent").addClass("hidden");
        $("ul.continents").find("#"+continent).removeClass("hidden");
    }

};

return DistributorList;
});
}).apply(window);/**!!<[ModuleDistributorList_com]!!**/
/**!![ModuleCarousel_com]>!!**/
(function(){
registerModule("ModuleCarousel", "com", function() {
var autoPlay = 0;

if(view.$.data("module-autoplay") == "True")
	autoPlay = view.$.data("module-time") * 1000;


var config = {
    scope: view.$,
    autoRotationTimer: autoPlay
}

new (Helpers("carousel"))(config);

var $slides = $(".promo-wrapper", view.$);

$slides.each(function () {
    $("<div class=\"container container-zoomzoom\"><div class=\"zoomzoom\"></div></div>").insertBefore($(this));
});
});
}).apply(window);/**!!<[ModuleCarousel_com]!!**/
/**!![ModuleConfigurationTool_com]>!!**/
(function(){

new function() {
    this["templates"] = this["templates"] || {};
this["templates"]["_configurationTool"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  return "<div class=\"render_div\" style=\"width: 100%; height:690px\"></div>\n<div class=\"nav-area\"></div>\n<div class=\"zoom-area\"></div>\n<div class=\"selection-area\"></div>\n<div class=\"error-message\">\n<h4>Sorry your browser is not compatible with the configurator tool</h4>\n</div>";
  },"useData":true});
this["templates"]["_location"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "		<li class=\""
    + escapeExpression(((helper = (helper = helpers.time || (depth0 != null ? depth0.time : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"time","hash":{},"data":data}) : helper)))
    + "\" >\n			<a href=\"#\" data-code=\""
    + escapeExpression(((helper = (helper = helpers.code || (depth0 != null ? depth0.code : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"code","hash":{},"data":data}) : helper)))
    + "\">"
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "</a>\n		</li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "<div class=\"location\">\n	<div class=\"location-button\">\n		<span>"
    + escapeExpression(((helper = (helper = helpers.location || (depth0 != null ? depth0.location : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"location","hash":{},"data":data}) : helper)))
    + "</span>\n	</div>\n	<ul class=\"location-list visablity-none\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.data : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "	</ul>\n<div>";
},"useData":true});
this["templates"]["_roof"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  return "<div class=\"roof-button up\">\n	<div class=\"icon\"></div>\n	<span></span>\n<div>";
  },"useData":true});
this["templates"]["_section"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, buffer = "	<li class=\"item-holder\">\n		<ul>\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.section : depth0), {"name":"each","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "		</ul>\n	</li>\n";
},"2":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "			<li data-code=\""
    + escapeExpression(((helper = (helper = helpers.code || (depth0 != null ? depth0.code : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"code","hash":{},"data":data}) : helper)))
    + "\" class=\"item item-"
    + escapeExpression(((helper = (helper = helpers.sectionCounter || (depth0 != null ? depth0.sectionCounter : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"sectionCounter","hash":{},"data":data}) : helper)))
    + "\">\n				<div class=\"color-block-outer\">\n					<div class=\"color-block\" style=\"background-color: "
    + escapeExpression(((helper = (helper = helpers.colorCode || (depth0 != null ? depth0.colorCode : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"colorCode","hash":{},"data":data}) : helper)))
    + ";\"> </div>\n				</div>\n				<span>\n					"
    + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper)))
    + "\n				</span>\n			</li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1;
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.data : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { return stack1; }
  else { return ''; }
  },"useData":true});
this["templates"]["_sectionList"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
  var stack1, buffer = "		<li>\n			<ul class=\"sections\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.section : depth0), {"name":"each","hash":{},"fn":this.program(2, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "			</ul>\n		</li>\n";
},"2":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "				<li>\n					<a href=\"#\" data-id=\""
    + escapeExpression(((helper = (helper = helpers.dataId || (depth0 != null ? depth0.dataId : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"dataId","hash":{},"data":data}) : helper)))
    + "\">"
    + escapeExpression(((helper = (helper = helpers.sectionName || (depth0 != null ? depth0.sectionName : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"sectionName","hash":{},"data":data}) : helper)))
    + "</a>\n				</li>\n";
},"4":function(depth0,helpers,partials,data) {
  var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
  return "			<li class=\"section-"
    + escapeExpression(((helper = (helper = helpers.dataId || (depth0 != null ? depth0.dataId : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"dataId","hash":{},"data":data}) : helper)))
    + " section visibility-hidden\" style=\"right: "
    + escapeExpression(((helper = (helper = helpers.right || (depth0 != null ? depth0.right : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"right","hash":{},"data":data}) : helper)))
    + "%;\">\n				<a href=\"#\" class=\"mobile-name\" data-id=\""
    + escapeExpression(((helper = (helper = helpers.dataId || (depth0 != null ? depth0.dataId : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"dataId","hash":{},"data":data}) : helper)))
    + "\">"
    + escapeExpression(((helper = (helper = helpers.sectionName || (depth0 != null ? depth0.sectionName : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"sectionName","hash":{},"data":data}) : helper)))
    + "</a>\n				<div class=\"section-overlay\" data-id=\""
    + escapeExpression(((helper = (helper = helpers.dataId || (depth0 != null ? depth0.dataId : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"dataId","hash":{},"data":data}) : helper)))
    + "\"></div>\n				<div class=\"section-list-wrapper\">\n					<ul class=\"item-list\">\n\n					</ul>\n					<div class=\"pagination\"></div>\n				</div>\n				<div class=\"item-arrow-left arrow-left-"
    + escapeExpression(((helper = (helper = helpers.dataId || (depth0 != null ? depth0.dataId : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"dataId","hash":{},"data":data}) : helper)))
    + "\"></div>\n				<div class=\"item-arrow-right arrow-right-"
    + escapeExpression(((helper = (helper = helpers.dataId || (depth0 != null ? depth0.dataId : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"dataId","hash":{},"data":data}) : helper)))
    + "\"></div>\n				\n			</li>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  var stack1, buffer = "<div class=\"section-list\">\n	<ul class=\"main-section-desktop\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.desktopSection : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  buffer += "	</ul>\n	<div class=\"section-holder\">\n		<ul class=\"section-items\">\n";
  stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.section : depth0), {"name":"each","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data});
  if (stack1 != null) { buffer += stack1; }
  return buffer + "		</ul>\n	</div>\n	<div class=\"arrow-left\"></div>\n	<div class=\"arrow-right\"></div>\n\n<div>";
},"useData":true});
this["templates"]["_zoom"] = Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
  return "<div class=\"zoom-wrapper\">\n	<div class=\"zoom-holder\">\n		<div class=\"zoom-line\"></div>\n		<div class=\"zoom-button\"></div>\n	</div>\n	<div class=\"zoom-button-open\"></div>\n	<div class=\"reset-button\"></div>\n</div>";
  },"useData":true});

    for (var template in this.templates) {
        Handlebars.registerPartial(template, this.templates[template]);
        window.registerTemplate('ModuleConfigurationTool.' + template,
            this.templates[template]);
    }

    return this.templates;
}

registerModule("ModuleConfigurationTool", "com", function() {
var $__Object$defineProperties = Object.defineProperties;

var Locations = function() {
    "use strict";

    function Locations(template, language, translations, places, pageWindow, selectionCallback) {
        this.language = language;
        this.translations = translations;
        this.roofState = false;
        this.selectionCallback = selectionCallback;
        this.templateData = [];
        this.templateData.location = "Locations";
        this.templateData.data = [];
        this.$document = $(pageWindow.document);

        for(var i = 0; i < places.length; i++) {
            this.templateData.data.push({
				name: places[i].name[this.language],
				code: places[i].id,
				time: places[i].dayTime == "true" ? "day" : "night"
			});
        }

        $(".nav-area").append(template._location(this.templateData));

        this.init();
    }

    $__Object$defineProperties(Locations.prototype, {
        init: {
            value: function() {
                this.$locationList = $(".location-list li a");
                this.$locationMenu = $(".location-list");
                this.$locationButton = $(".location-button");

                view.$.on("click", ".location-button", function(e) {
                    e.stopPropagation();
                    e.preventDefault();
                    this.toggleLocationBtn();
                }.bind(this));

                view.$.on("click", ".location-list li", function(e) {
                    e.stopPropagation();
                    e.preventDefault();
                    this.toggleLocationBtn();
                    this.$locationList.removeClass("selected");
                    $(e.target).addClass("selected");
                    $(e.target).data("code");
                    this.selectionCallback.call(this, $(e.target).data("code"));
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        toggleLocationBtn: {
            value: function(close) {
                if(close){
                    this.$locationMenu.removeClass("active");
                    this.$locationButton.removeClass("active");
                }else
                {
                    this.$locationMenu.toggleClass("active");
                    this.$locationButton.toggleClass("active");
                }




                if(this.$locationMenu.hasClass("active")){
                    this.$locationMenu.removeClass("visablity-none");

                    this.$document.bind("click", function(e) {
                        this.$document.unbind("click");
                        this.toggleLocationBtn("close");
                    }.bind(this));
                }else {
                    this.$document.unbind("click");
                    this.$locationMenu.on("transitionend webkitTransitionEnd", function () {
                        this.$locationMenu.unbind("transitionend webkitTransitionEnd");
                        this.$locationMenu.addClass("visablity-none");
                    }.bind(this));
                }
            },

            enumerable: false,
            writable: true
        }
    });

    return Locations;
}();
var $__Object$defineProperties = Object.defineProperties;

var Roof = function() {
    "use strict";

    function Roof(template, language, translations, selectionCallback) {
        this.language = language;
        this.translations = translations;
        this.roofState = false;
        this.selectionCallback = selectionCallback;
        $(".nav-area").append(template._roof());

        this.init();
    }

    $__Object$defineProperties(Roof.prototype, {
        init: {
            value: function() {
                var $roofButton = $(".roof-button");
                var $roofText = $roofButton.find("span");

                $roofText.empty().append(this.translations.roofUp[this.language]);
                view.$.on("click", ".roof-button", function(e) {
                    e.stopPropagation();
                    e.preventDefault();
                    var text = "";

                    $roofButton.toggleClass("up");
                    $roofButton.toggleClass("down");

                    if(this.roofState) {
                        this.roofState = false;
                        text = this.translations.roofUp[this.language];
                    }else {
                        this.roofState = true;
                        text = this.translations.roofDown[this.language];
                    }
                    $roofText.empty().append(text);
                    this.selectionCallback.call(this, this.roofState);
                }.bind(this));
            },

            enumerable: false,
            writable: true
        }
    });

    return Roof;
}();
var $__Object$defineProperties = Object.defineProperties;

var Section = function() {
    "use strict";

    function Section(template, language, data, id, pageWindow, selectionCallback) {
        this.template = template;
        this.language = language;
        this.data = data;
        this.id = id;
        this.selectionCallback = selectionCallback;
        this.$sectionSelctor = view.$.find(".section-items .section-"+this.id);
        this.tabPosition = 0;
        this.$pagewindow = pageWindow;
        this.buildData();
    }

    $__Object$defineProperties(Section.prototype, {
        init: {
            value: function() {},
            enumerable: false,
            writable: true
        },

        buildData: {
            value: function() {
                var dataLength = this.data.data.length,
                    sectionCounter = 0,
                    sectionData = [];
                sectionData.data = [];
                sectionData.api_name = this.data.api_name;
                this.itemSections = Math.ceil(dataLength / 5);

                for(var i=0; i < this.itemSections; i++) {
                    var tab = [];
                    tab.section = [];

                    for(var j=0; j < 5 && sectionCounter < dataLength; j++) {
                        var temp = this.data.data[sectionCounter];
                        tab.section.push({
                            name: temp.name[this.language],
                            code: temp.code,
                            image: temp.image,
                            colorCode: temp.colorCode,
                            sectionCounter: sectionCounter
                        });
                        sectionCounter ++;
                    }
                    sectionData.data.push(tab);
                }

                this.$sectionSelctor.find(".item-list").append(this.template._section(sectionData)).attr("style", "width:"+(100*this.itemSections)+"%;");
                this.$sectionSelctor.find(".item-list .item-holder").attr("style", "width:"+(100/this.itemSections)+"%;");
                this.$sectionSelctor.find(".item-list .item-holder:first-child li:first-child").addClass("selected");
                this.buildPagination();
                this.$sectionSelctor.find(".item-arrow-left").attr("style", "display: none;");
            },

            enumerable: false,
            writable: true
        },

        buildPagination: {
            value: function() {
                this.$pagination = this.$sectionSelctor.find(".pagination");
                var selected = "selected";
                if(this.itemSections){
                    for(var i = 0; i < this.itemSections; i++){
                        this.$pagination.append("<a href=\"#\" class=\"pagination-item pagination-"+i+" "+selected+"\" data-id=\""+i+"\"></a>");
                        selected = "";
                    }
                }

                this.buildEventListeners();
            },

            enumerable: false,
            writable: true
        },

        buildEventListeners: {
            value: function() {
                view.$.on("click", ".section-items .section-"+this.id+" .item", function(e) {
                    e.stopPropagation();
                    e.preventDefault();
                    this.$sectionSelctor.find(".item").removeClass("selected");
                    $(e.currentTarget).addClass("selected");
                    this.$sectionSelctor.removeClass("selected");
                    this.selectionCallback.call(this, this.data.api_name, $(e.currentTarget).data("code"), this.id);
                }.bind(this));

                view.$.on("click", ".section-items .section-"+this.id+" .item-arrow-left", function(e) {
                    e.stopPropagation();
                    e.preventDefault();
                    if(this.tabPosition > 0){
                        this.tabPosition --;
                        this.moveList();
                    }
                }.bind(this));

                view.$.on("click", ".section-items .section-"+this.id+" .item-arrow-right", function(e) {
                    e.stopPropagation();
                    e.preventDefault();
                    if(this.tabPosition < (this.itemSections - 1)){
                        this.tabPosition ++;
                        this.moveList();
                    }
                }.bind(this));

                view.$.on("click touchstart", ".section-items .section-"+this.id+" .pagination-item", function(e) {
                    e.stopPropagation();
                    e.preventDefault();
                    this.tabPosition = $(e.target).data("id");
                    this.moveList();
                }.bind(this));


                this.buildMobile();
            },

            enumerable: false,
            writable: true
        },

        buildMobile: {
            value: function() {
                var sectionPos = Math.floor((this.$pagewindow.height() - 70) / 3);
                if(this.isMobile) {}
            },

            enumerable: false,
            writable: true
        },

        moveList: {
            value: function() {
                this.$sectionSelctor.find(".item-list").attr("style", "left:-"+(100*this.tabPosition)+"%; width:"+(100*this.itemSections)+"%;");
                this.$pagination.find(".pagination-item").removeClass("selected");
                this.$pagination.find(".pagination-"+this.tabPosition).addClass("selected");

                if(this.tabPosition == 0)
                    this.$sectionSelctor.find(".item-arrow-left").attr("style", "display: none;");
                else
                    this.$sectionSelctor.find(".item-arrow-left").attr("style", "");

                if(this.tabPosition == (this.itemSections-1))
                    this.$sectionSelctor.find(".item-arrow-right").attr("style", "display: none;")
                else
                    this.$sectionSelctor.find(".item-arrow-right").attr("style", "");
            },

            enumerable: false,
            writable: true
        },

        isMobile: {
            value: function() {
                return this.pageWindow.innerWidth < 768;
            },

            enumerable: false,
            writable: true
        }
    });

    return Section;
}();
var $__Object$defineProperties = Object.defineProperties;

var SectionList = function() {
    "use strict";

    function SectionList(template, language, data, pagewindow, selectionCallback) {
        this.data = data;
        this.template = template;
        this.language = language;
        this.templateData = [];
        this.desktopTab = 0;
        this.desktopSections = Math.ceil(this.data.length / 3);
        this.selectionCallback = selectionCallback;
        this.$pagewindow = $(pagewindow);
        this.buildData(template);
    }

    $__Object$defineProperties(SectionList.prototype, {
        init: {
            value: function() {},
            enumerable: false,
            writable: true
        },

        buildData: {
            value: function(template) {
                this.templateData.desktopSection = [];
                this.templateData.section = [];
                var sectionLength = this.data.length,
                    sectionCounter = 0;
                this.sections = Math.ceil(this.data.length / 3);

                for(var i=0; i < this.sections; i++) {
                    var temp = [];
                    temp.section = [];
                    for(var j=0; j < 3 && sectionCounter < sectionLength; j++) {
                        temp.section.push({
                            sectionName: this.data[sectionCounter].name[this.language],
                            dataId: sectionCounter,
                            apiName: this.data[sectionCounter].api_name
                        });
                        sectionCounter ++;
                    }
                    this.templateData.desktopSection.push(temp);
                }

                for(var i=0; i < sectionLength; i++){
                    this.templateData.section.push({
                        sectionName: this.data[i].name[this.language],
                        dataId: i,
                        apiName: this.data[i].api_name,
                        right: 100 * i
                    });
                }

                $(".selection-area").append(template._sectionList(this.templateData));
                $(".main-section-desktop").attr("style", "width:"+(100*this.sections)+"%");
                $(".main-section-desktop > li").attr("style", "width:"+(100/this.sections)+"%");

                if(sectionLength <= 1)
                    view.$.find(".sections li").attr("style", "width: 100%;");

                this.buildSection();
                this.addEventListeners();
                this.buildMobile();
            },

            enumerable: false,
            writable: true
        },

        addEventListeners: {
            value: function() {
                view.$.on("click", ".arrow-left", function(e) {
                    e.stopPropagation();
                    e.preventDefault();
                    if(this.desktopTab > 0) {
                        this.desktopTab --;
                        this.moveSectionList();
                    }
                }.bind(this));

                view.$.on("click", ".arrow-right", function(e) {
                    e.stopPropagation();
                    e.preventDefault();
                    if(this.desktopTab < (this.desktopSections - 1)) {
                        this.desktopTab ++;
                        this.moveSectionList();
                    }
                }.bind(this));

                view.$.on("click", ".section .mobile-name, .section .section-overlay", function(e) {
                    e.stopPropagation();
                    e.preventDefault();
                    var $target = view.$.find(".section-"+$(e.target).data("id"));
                    $target.toggleClass("selected");
                    if($target.hasClass("selected")) {
                        $target.attr("style", "top: 0;");
                        $target.find(".item-list").attr("style", "height: "+(this.sectionPos * 2 - 49)+"px; width:"+(100*this.sections)+"%");
                    }
                    else {
                        $target.attr("style", "top: "+ this.sectionPos +"px;");
                    }
                }.bind(this));

                view.$.on("click", ".sections > li a", function(e) {
                    var $target = view.$.find(".section-"+$(e.target).data("id"));
                    $(e.target).toggleClass("selected");
                    $target.toggleClass("selected");
                    if($target.hasClass("selected")){
                        $target.removeClass("visibility-hidden");
                    }else {
                        $target.on("transitionend webkitTransitionEnd", function () {
                            $target.unbind("transitionend webkitTransitionEnd");
                            $target.addClass("visibility-hidden");
                        });
                    }
                });
            },

            enumerable: false,
            writable: true
        },

        moveSectionList: {
            value: function() {
                $(".main-section-desktop").attr("style", "width:"+(100*this.desktopSections)+"%; left:-"+100*this.desktopTab+"%");
            },

            enumerable: false,
            writable: true
        },

        buildSection: {
            value: function() {
                for(var i=0; i < this.data.length; i++){
                    new Section(this.template, this.language, this.data[i], i, this.$pagewindow, function(apiName, sectionCode, id) {
                        view.$.find(".section-items .section-"+id).attr("style", "top: "+ this.sectionPos +"px;");
                        this.selectionCallback.call(this, apiName, sectionCode);
                    }.bind(this));
                }
            },

            enumerable: false,
            writable: true
        },

        buildMobile: {
            value: function() {
                this.sectionPos = Math.floor((this.$pagewindow.height() - 70) / 3);
                if(this.isMobile) {
                    view.$.find(".selection-area").attr("style", "top: "+this.sectionPos+"px;");
                    view.$.find(".section").attr("style", "top: "+this.sectionPos+"px;");
                }
                view.$.find(".section").removeClass("selected");
                view.$.find(".section").addClass("visibility-hidden");
            },

            enumerable: false,
            writable: true
        },

        isMobile: {
            value: function() {
                return this.pageWindow.innerWidth < 768;
            },

            enumerable: false,
            writable: true
        }
    });

    return SectionList;
}();
var $__Object$defineProperties = Object.defineProperties;

var Zoom = function() {
    "use strict";

    function Zoom(template, pagewindow, selectionCallback, resetCallback) {
        this.$document = $(pagewindow.document);
        this.template = template;
        this.selectionCallback = selectionCallback;
        this.resetCallback = resetCallback;
        this.init();
    }

    $__Object$defineProperties(Zoom.prototype, {
        init: {
            value: function() {
                view.$.find(".zoom-area").append(this.template._zoom());
                this.buildEventListeners();
            },

            enumerable: false,
            writable: true
        },

        buildEventListeners: {
            value: function() {
                this.sliding = false;
                this.zoomBtn = view.$.find(".zoom-area .zoom-button");
                this.slideHeight = view.$.find(".zoom-line").height();
                this.slideOffset = view.$.find(".zoom-line").offset().top;

                var $zoomArea = view.$.find(".zoom-area");

                view.$.on("click touchend", ".zoom-area .reset-button", function(e) {
                    this.setZoomButtonPosition(0);
                    this.calculateZoom();
                    this.resetCallback.call();
                }.bind(this));

                view.$.on("click", ".zoom-area .zoom-button-open", function(e) {
                    e.stopImmediatePropagation();
                    e.stopPropagation();
                    e.preventDefault();
                    $zoomArea.toggleClass("open");
                    this.checkZoomSize();
                }.bind(this));


                view.$.on("mousedown touchstart", ".zoom-area .zoom-button", function(e) {
                    this.sliding = true;
                    console.log("touch start");
                    this.$document.mousemove(function(e){
                        if(this.sliding) {
                            var calc = (e.clientY-60)-this.slideOffset;
                            if(calc >= 0 && calc <= this.slideHeight)
                                this.zoomBtn.attr("style", "bottom: "+(this.slideHeight - calc)+"px;");
                        }
                    }.bind(this));

                    this.$document.bind("touchmove", function(e) {
                        console.log(e);
                        e.preventDefault();
                        if(this.sliding) {
                            var calc = e.originalEvent.touches[0].clientY-this.slideOffset;
                            if(calc >= 0 && calc <= this.slideHeight)
                                this.zoomBtn.attr("style", "bottom: "+(this.slideHeight - calc)+"px;");
                        }
                    }.bind(this));
                }.bind(this));

                this.$document.mouseup(function(){
                    if(this.sliding) {
                        view.$.find(".zoom-area").removeClass("open");
                        this.sliding = false;
                        this.$document.unbind( "mousemove" );
                        this.calculateZoom();
                    }
                }.bind(this));


                this.$document.bind("touchend", function(e) {
                    if(this.sliding) {
                        view.$.find(".zoom-area").removeClass("open");
                        this.sliding = false;
                        this.$document.unbind( "touchmove" );
                        this.calculateZoom();
                    }
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        setZoomButtonPosition: {
            value: function(zoomLevel) {
                this.zoomBtn.attr("style", "bottom: "+(this.slideHeight / 100 * zoomLevel)+"px;");
            },

            enumerable: false,
            writable: true
        },

        calculateZoom: {
            value: function() {
                this.selectionCallback.call(this, parseFloat(this.zoomBtn.css("bottom"),10) / this.slideHeight * 100);
            },

            enumerable: false,
            writable: true
        },

        checkZoomSize: {
            value: function() {
                if(view.$.find(".render_div").height() < 633) {
                    view.$.find(".zoom-area .zoom-line").attr("style", "height:"+(view.$.find(".render_div").height()-160)+"px");
                    this.slideHeight = view.$.find(".zoom-line").height();

                    this.slideOffset = view.$.find(".zoom-line").offset().top;

                    view.$.find(".zoom-area").addClass("small");
                }
            },

            enumerable: false,
            writable: true
        }
    });

    return Zoom;
}();
/*
 * main.js
 *
 * This file represents the module application entry point
 *
 * The following variables are provided:
 *
 *	scope [HTMLElement] - the module's HTML element
 *	$ - a reference to the jQuery library
 *
 * Example on how to access the module's root element using jQuery:
 *
 *	var $scope = $(scope);
 */

var $__Object$defineProperties = Object.defineProperties;

var ConfigurationTool = function() {
    "use strict";

    function ConfigurationTool() {
        this.Templates = {
            _roof: Services("templateService").templates("ModuleConfigurationTool._roof"),
            _location: Services("templateService").templates("ModuleConfigurationTool._location"),
            _sectionList: Services("templateService").templates("ModuleConfigurationTool._sectionList"),
            _configurationTool: Services("templateService").templates("ModuleConfigurationTool._configurationTool"),
            _section: Services("templateService").templates("ModuleConfigurationTool._section"),
            _zoom: Services("templateService").templates("ModuleConfigurationTool._zoom")
        };

        this.init();
    }

    $__Object$defineProperties(ConfigurationTool.prototype, {
        init: {
            value: function() {
                this.language = view.$.data("language");
                this.translations = view.$.data("translation");
                this.configuration = view.$.data("configuration");

                view.$.append(this.Templates._configurationTool());

                this.param = {};
                this.param["model"] = this.configuration.car_code;
                this.param["color"] = "41V";
                this.param["oes"] = [];
                this.param["open"] = false;

                setTimeout(function() {
                    this.loadTool.call(this, Services("pagetools"));
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        buildUi: {
            value: function() {
                new Roof(this.Templates, this.language, this.translations, function(selection) {
                    this.param["open"] = selection;
                    this.changeConfigurator();
                }.bind(this));

                if(this.configuration.sections.length > 1){
                    // hard code section to only show one we don't have design for anyother sections yet
                    this.configuration.sections = [this.configuration.sections[0]];
                }

                this.zoomUi = new Zoom(this.Templates, this.pageWindow, function(selection) {
                    this.zoomValue = selection;

                    this.co.SetDolly(this.zoomValue);
                }.bind(this), function() {
                    this.firstLoad = true;
                    this.co.ResetCamera(true);
                }.bind(this));

                new Locations(this.Templates, this.language, this.translations, this.configuration.locations, this.pageWindow, function(selection) {
                    if(this.param["env"] != selection) {
                        this.param["env"] = selection;
                        this.changeConfigurator();
                    }
                }.bind(this));

                this.sectionUi = new SectionList(this.Templates, this.language, this.configuration.sections, this.pageWindow, function(apiName, selection) {
                    if(this.param[apiName] != selection) {
                        this.param[apiName] = selection;
                        this.changeConfigurator();
                    }
                }.bind(this));

                this.addEventListeners();
            },

            enumerable: false,
            writable: true
        },

        loadTool: {
            value: function(pagetools) {
                this.firstLoad = true;
                this.pagetools = pagetools;
                this.pageWindow = pagetools.window._element[0];

                this.pageWindow.onChangeDolly = function(dValue){
                    this.zoomValue = Math.floor(dValue);
                    if(this.firstLoad){
                        this.zoomValue = 0;
                        this.firstLoad = false;
                    }

                    this.co.SetDolly(this.zoomValue);
                    this.zoomUi.setZoomButtonPosition(this.zoomValue);
                }.bind(this);


                this.pageSizeIsMobile = "unset";
                this.setSize();
                // Initialize Options
                var options = {
                    car: this.configuration.car_code,
                    enableWheelDolly: true,
                    onChangeDolly: this.pageWindow.onChangeDolly,
                    fov: 0					
                };
                this.ua = this.pageWindow.navigator.userAgent;
                var ver = this.iOSversion();

                var err = false;

                if(this.detectIE() && this.detectIE() < 11){
                    err = true;
                }
                else if(this.detectWindows() || (ver && ver[0] < 8)){
                    err = true;
                }

                if(err)
                    view.$.find(".error-message").show();
                else {
                    if(this.pageWindow.ConfiguratorView)
                        this.co = new this.pageWindow.ConfiguratorView($(".render_div"), options);
                    else
                        alert("Configurator API is unavailable");
                    this.buildUi();
                }

                if(this.detectIE() && this.detectIE() == 9)
                    this.ie9fix();
            },

            enumerable: false,
            writable: true
        },

        setSize: {
            value: function() {
                if(this.pageSizeIsMobile == "unset"){
                    this.pageSizeIsMobile = this.isMobile();
                }else{
                    this.sectionUi.buildMobile();
                }

                view.$.find(".render_div").attr("style", "width: 100%; height:690px");
                view.$.attr("style","");
                if(this.isMobile()) {
                    view.$.find(".render_div").attr("style", "width: 100%; height:"+Math.floor((($(this.pageWindow).height())-70-($(this.pageWindow).height() / 3)+24))+"px;");
                    view.$.attr("style", "height: " + ($(this.pageWindow).height()-70) + "px");
                    view.$.find(".zoom-area").attr("style", "height:"+Math.floor((($(this.pageWindow).height())-70-30-($(this.pageWindow).height() / 3)+24))+"px;");
                }else {
                    if($(this.pageWindow).height()-138-65 < 690) {
                        view.$.find(".render_div").attr("style", "width: 100%; height:"+($(this.pageWindow).height()-138-65)+"px;");
                        view.$.find(".zoom-area").addClass("small");
                        view.$.find(".zoom-area").attr("style", "");
                    }
                }

                if(view.$.find(".render_div").height() < 350) {
                    view.$.find(".zoom-area").addClass("small");
                }
            },

            enumerable: false,
            writable: true
        },

        addEventListeners: {
            value: function() {
                $(".render_div").bind("touchmove", function(e){
                    if (e.originalEvent.touches.length === 2) {
                        if(this.tracks.length == 0){
                            this.tracks.push({
                                x: e.originalEvent.touches[0].pageX,
                                y: e.originalEvent.touches[0].pageY
                            });

                            this.tracks.push({
                                x: e.originalEvent.touches[1].pageX,
                                y: e.originalEvent.touches[1].pageY
                            });

                            this.topFinger = e.originalEvent.touches[0].pageY < e.originalEvent.touches[1].pageY ? 0 : 1 ;
                            this.bottomFinger = e.originalEvent.touches[0].pageY > e.originalEvent.touches[1].pageY ? 0 : 1 ;


                            this.leftFinger = e.originalEvent.touches[0].pageX < e.originalEvent.touches[1].pageX ? 0 : 1 ;
                            this.rightFinger = e.originalEvent.touches[0].pageX > e.originalEvent.touches[1].pageX ? 0 : 1 ;
                        }else{
                            var track =  this.tracks[0];
                            if(((this.tracks[this.bottomFinger].y - this.tracks[this.topFinger].y) > (e.originalEvent.touches[this.bottomFinger].pageY - e.originalEvent.touches[this.topFinger].pageY)) && e.originalEvent.touches[this.topFinger].pageY > this.tracks[this.topFinger].y + 5){
                                this.tracks = [];

                                this.tracks.push({
                                    x: e.originalEvent.touches[0].pageX,
                                    y: e.originalEvent.touches[0].pageY
                                });

                                this.tracks.push({
                                    x: e.originalEvent.touches[1].pageX,
                                    y: e.originalEvent.touches[1].pageY
                                });

                                this.zoomValue = this.zoomValue + 10;
                                if(this.zoomValue > 100)
                                    this.zoomValue = 100;
                                this.co.SetDolly(this.zoomValue);

                                this.zoomUi.setZoomButtonPosition(this.zoomValue);
                            }


                            if(((this.tracks[this.bottomFinger].y - this.tracks[this.topFinger].y) < (e.originalEvent.touches[this.bottomFinger].pageY - e.originalEvent.touches[this.topFinger].pageY))  && e.originalEvent.touches[this.topFinger].pageY+5 < this.tracks[this.topFinger].y ){
                                this.tracks = [];

                                this.tracks.push({
                                    x: e.originalEvent.touches[0].pageX,
                                    y: e.originalEvent.touches[0].pageY
                                });

                                this.tracks.push({
                                    x: e.originalEvent.touches[1].pageX,
                                    y: e.originalEvent.touches[1].pageY
                                });

                                this.zoomValue = this.zoomValue -10;
                                if(this.zoomValue < 0)
                                    this.zoomValue = 0;
                                this.co.SetDolly(this.zoomValue);

                                this.zoomUi.setZoomButtonPosition(this.zoomValue);
                            }
                        }
                    }
                }.bind(this)).on("touchstart", function () {
                    //start-over
                    this.tracks = [];
                }.bind(this)).on("touchend", function () {}.bind(this));

                this.pagetools.window.on("resize", function() {
                    if(this.pageSizeIsMobile != this.isMobile()){
                        this.pageSizeIsMobile = this.isMobile();
                        this.setSize();
                    }
                }.bind(this));
            },

            enumerable: false,
            writable: true
        },

        changeConfigurator: {
            value: function() {
                this.co.ChangeConfiguration(this.param);
            },

            enumerable: false,
            writable: true
        },

        isMobile: {
            value: function() {
                return this.pageWindow.innerWidth < 768;
            },

            enumerable: false,
            writable: true
        },

        detectIE: {
            value: function() {
                var ua = this.pageWindow.navigator.userAgent;



                var msie = ua.indexOf("MSIE ");
                if (msie > 0) {
                    // IE 10 or older => return version number
                    return parseInt(ua.substring(msie + 5, ua.indexOf(".", msie)), 10);
                }

                var trident = ua.indexOf("Trident/");
                if (trident > 0) {
                    // IE 11 => return version number
                    var rv = ua.indexOf("rv:");
                    return parseInt(ua.substring(rv + 3, ua.indexOf(".", rv)), 10);
                }

                var edge = ua.indexOf("Edge/");
                if (edge > 0) {
                    // Edge (IE 12+) => return version number
                    return parseInt(ua.substring(edge + 5, ua.indexOf(".", edge)), 10);
                }

                // other browser
                return false;
            },

            enumerable: false,
            writable: true
        },

        detectWindows: {
            value: function() {
                if((this.ua.indexOf("Windows NT 6.1") != -1 && this.ua.indexOf("Windows NT 6.0")  && this.ua.indexOf("Windows NT 5.1")  && this.ua.indexOf("Windows NT 5.0")))
                {
                    if(this.ua.toLowerCase().indexOf("chrome") > -1) {
                        view.$.addClass("hideZoom");
                        return false;
                    }

                    /*if(this.ua.toLowerCase().indexOf('firefox') > -1) {
                        return true;
                    }*/;
                }
            },

            enumerable: false,
            writable: true
        },

        iOSversion: {
            value: function() {
                if (/iP(hone|od|ad)/.test(this.ua)) {
                    // supports iOS 2.0 and later: <http://bit.ly/TJjs1V>
                    var v = (this.ua).match(/OS (\d+)_(\d+)_?(\d+)?/);
                    return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)];
                }
            },

            enumerable: false,
            writable: true
        },

        ie9fix: {
            value: function() {
                //This is a Hack need to fix this
                view.$.find(".render_div").attr("style", "height:690px; background-color:#000000;");
                view.$.attr("style", "height:690px; background-color:#000000; position: relative;");
                view.$.find(".error-message").attr("style", "width: 400px; margin: 0 auto; position: absolute; top: 40px; left: 0; right: 0; bottom: 0; text-align: center;");
            },

            enumerable: false,
            writable: true
        }
    });

    return ConfigurationTool;
}();

return ConfigurationTool;
});
}).apply(window);/**!!<[ModuleConfigurationTool_com]!!**/
